---
title: 构建 join filter 时，表达式计算 core-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于 构建 join filter 时，表达式计算 core相关的常见问题和使用技巧，帮助您快速解决 构建 join filter 时，表达式计算 core的难题。
---
切换语言

- 简体中文
- English

划线反馈

# 构建 join filter 时，表达式计算 core

更新时间：2026-05-14 07:41

适用版本： V4.3.x 内容类型：Troubleshoot  

## 问题现象

遇到这个问题可能会 core 掉。

可以从计划上判断是否存是这个问题导致，比如下面这个计划中，**2 号 hash join 中有一个 join key 左侧是 `cast(length(t1.c2), DECIMAL(20, 0))`，但是这个表达式没有分配在 3 号 join filter 中**。

```shell
-- 一个触发 core 的例子
create table t1(c1 bigint, c2 varchar(2000));
create table t2(c1 bigint, c2 varchar(2000));
create table t3(c1 bigint, c2 varchar(2000));

insert into t1 select random(123) , repeat('0123456789', 120) from table(generator(300));
insert into t1 select random(123) , "123" from table(generator(500));

insert into t2 select random(123) , repeat('0123456789', 100) from table(generator(80));
insert into t2 select random(123) , "123" from table(generator(100));

insert into t3 select random(123) , repeat('0123456789', 100) from table(generator(80));
insert into t3 select random(123) , "123" from table(generator(100));

explain basic select /*+
    BEGIN_OUTLINE_DATA
    LEADING(@"SEL$1" ("test"."t1"@"SEL$1" ("test"."t2"@"SEL$1" "test"."t3"@"SEL$1")))
    USE_HASH(@"SEL$1" ("test"."t3"@"SEL$1" "test"."t2"@"SEL$1"))
    PQ_DISTRIBUTE(@"SEL$1" ("test"."t3"@"SEL$1" "test"."t2"@"SEL$1") BC2HOST NONE)
    PX_JOIN_FILTER(@"SEL$1" "test"."t2"@"SEL$1" "test"."t1"@"SEL$1")
    NO_PX_JOIN_FILTER(@"SEL$1" "test"."t3"@"SEL$1" "test"."t1"@"SEL$1")
    PARALLEL(@"SEL$1" "test"."t1"@"SEL$1" 2)
    FULL(@"SEL$1" "test"."t1"@"SEL$1")
    USE_HASH(@"SEL$1" "test"."t3"@"SEL$1")
    PQ_DISTRIBUTE(@"SEL$1" "test"."t3"@"SEL$1" BC2HOST NONE)
    PX_JOIN_FILTER(@"SEL$1" "test"."t3"@"SEL$1" "test"."t2"@"SEL$1")
    PARALLEL(@"SEL$1" "test"."t2"@"SEL$1" 2)
    FULL(@"SEL$1" "test"."t2"@"SEL$1")
    PARALLEL(@"SEL$1" "test"."t3"@"SEL$1" 2)
    FULL(@"SEL$1" "test"."t3"@"SEL$1")
    PARALLEL(2)
    OPTIMIZER_FEATURES_ENABLE('4.3.2.0')
    END_OUTLINE_DATA
*/
* from t1, t2, t3 where  length(t1.c2)=t3.c2 and t1.c2 = t2.c2 and t2.c1=t3.c1;
Query Plan
======================================================
|ID|OPERATOR                                |NAME    |
------------------------------------------------------
|0 |PX COORDINATOR                          |        |
|1 |└─EXCHANGE OUT DISTR                    |:EX10002|
|2 |  └─SHARED HASH JOIN                    |        |
|3 |    ├─join filter CREATE                |:RF0001 |
|4 |    │ └─EXCHANGE IN DISTR               |        |
|5 |    │   └─EXCHANGE OUT DISTR (BC2HOST)  |:EX10000|
|6 |    │     └─PX BLOCK ITERATOR           |        |
|7 |    │       └─TABLE FULL SCAN           |t1      |
|8 |    └─SHARED HASH JOIN                  |        |
|9 |      ├─join filter CREATE              |:RF0000 |
|10|      │ └─EXCHANGE IN DISTR             |        |
|11|      │   └─EXCHANGE OUT DISTR (BC2HOST)|:EX10001|
|12|      │     └─join filter USE           |:RF0001 |
|13|      │       └─PX BLOCK ITERATOR       |        |
|14|      │         └─TABLE FULL SCAN       |t2      |
|15|      └─join filter USE                 |:RF0000 |
|16|        └─PX BLOCK ITERATOR             |        |
|17|          └─TABLE FULL SCAN             |t3      |
======================================================
Outputs & filters:
-------------------------------------
  0 - output([INTERNAL_FUNCTION(t1.c1, t1.c2, t2.c1, t2.c2, t3.c1, t3.c2)]), filter(nil), rowset=256
  1 - output([INTERNAL_FUNCTION(t1.c1, t1.c2, t2.c1, t2.c2, t3.c1, t3.c2)]), filter(nil), rowset=256
      dop=2
  2 - output([t1.c2], [t3.c2], [t2.c2], [t1.c1], [t2.c1], [t3.c1]), filter(nil), rowset=256
      equal_conds([cast(length(t1.c2), DECIMAL(20, 0)) = cast(t3.c2, DECIMAL(-1, -1))], [t1.c2 = t2.c2]), other_conds(nil)
  3 - output([t1.c2], [t1.c1]), filter(nil), rowset=256
      RF_TYPE(in, range, bloom), RF_EXPR[t1.c2]
  4 - output([t1.c2], [t1.c1]), filter(nil), rowset=256
  5 - output([t1.c2], [t1.c1]), filter(nil), rowset=256
      dop=2
  6 - output([t1.c2], [t1.c1]), filter(nil), rowset=256
  7 - output([t1.c2], [t1.c1]), filter(nil), rowset=256
      access([t1.c2], [t1.c1]), partitions(p0)
      is_index_back=false, is_global_index=false,
      range_key([t1.__pk_increment]), range(MIN ; MAX)always true
  8 - output([t3.c2], [t2.c2], [t2.c1], [t3.c1]), filter(nil), rowset=256
      equal_conds([t2.c1 = t3.c1]), other_conds(nil)
  9 - output([t2.c2], [t2.c1]), filter(nil), rowset=256
      RF_TYPE(in, range, bloom), RF_EXPR[t2.c1]
 10 - output([t2.c2], [t2.c1]), filter(nil), rowset=256
 11 - output([t2.c2], [t2.c1]), filter(nil), rowset=256
      dop=2
 12 - output([t2.c2], [t2.c1]), filter(nil), rowset=256
 13 - output([t2.c2], [t2.c1]), filter(nil), rowset=256
 14 - output([t2.c2], [t2.c1]), filter([RF_IN_FILTER(t2.c2)], [RF_RANGE_FILTER(t2.c2)], [RF_BLOOM_FILTER(t2.c2)]), rowset=256
      access([t2.c2], [t2.c1]), partitions(p0)
      is_index_back=false, is_global_index=false, filter_before_indexback[false,false,false],
      range_key([t2.__pk_increment]), range(MIN ; MAX)always true
 15 - output([t3.c2], [t3.c1]), filter(nil), rowset=256
 16 - output([t3.c2], [t3.c1]), filter(nil), rowset=256
 17 - output([t3.c2], [t3.c1]), filter([RF_IN_FILTER(t3.c1)], [RF_RANGE_FILTER(t3.c1)], [RF_BLOOM_FILTER(t3.c1)]), rowset=256
      access([t3.c2], [t3.c1]), partitions(p0)
      is_index_back=false, is_global_index=false, filter_before_indexback[false,false,false],
      range_key([t3.__pk_increment]), range(MIN ; MAX)always true

```

## 关键诊断信息

### 触发条件

必要不充分条件：

1. **hash join 的左侧条件中需要有一个 join 等值条件的左侧是一个需要计算表达式，而非投影列**。
 2. **需要满足 hash join 的左侧输出的每一行数据占据的空间较大，满足每一行行长的均值大于 256 个字节**。

### 事前巡检

无。

### 事后诊断

通过 core 栈可以快速定位到是 join filter 算子做后构建的函数 `join_filter_create_do_material` 中计算表达式出现了问题，访问了非法内存，分析下来是表达式没有清理计算标记导致。

```shell
oceanbase::common::coredump_cb(int, int, void*, void*) at ??:?
?? ??:0
oceanbase::sql::ObExprTimestamp::calc_timestamp1(oceanbase::sql::ObExpr const&, oceanbase::sql::ObEvalCtx&, oceanbase::common::ObDatum&) at ??:?
oceanbase::sql::expr_default_eval_batch_func(oceanbase::sql::ObExpr const&, oceanbase::sql::ObEvalCtx&, oceanbase::sql::ObBitVectorImpl const&, long) at ??:?
oceanbase::sql::ObExpr::eval_vector(oceanbase::sql::ObEvalCtx&, oceanbase::sql::ObBitVectorImpl const&, oceanbase::sql::EvalBound const&) const at ??:?
oceanbase::sql::ObJoinFilterOp::join_filter_create_do_material(long) at 0_cxx.cxx:?
oceanbase::sql::ObJoinFilterOp::inner_get_next_batch(long) at 0_cxx.cxx:?
oceanbase::sql::ObOperator::get_next_batch(long, oceanbase::sql::ObBatchRows const*&) at ??:?
oceanbase::sql::ObHashJoinVecOp::inner_get_next_batch(long) at 0_cxx.cxx:?
oceanbase::sql::ObOperator::get_next_batch(long, oceanbase::sql::ObBatchRows const*&) at ??:?
oceanbase::sql::ObPxTransmitOp::next_vector(long) at 1_cxx.cxx:?
oceanbase::sql::ObPxDistTransmitOp::inner_get_next_batch(long) at ??:?
oceanbase::sql::ObOperator::get_next_batch(long, oceanbase::sql::ObBatchRows const*&) at ??:?
oceanbase::sql::ObPxTransmitOp::fetch_first_row() at 1_cxx.cxx:?
oceanbase::sql::ObPxTransmitOp::inner_open() at ??:?
oceanbase::sql::ObPxDistTransmitOp::inner_open() at ??:?
oceanbase::sql::ObOperator::open() at ??:?
oceanbase::sql::ObPxTaskProcess::process() at 0_cxx.cxx:?
oceanbase::sql::PxWorkerFunctor::operator()(bool) at 0_cxx.cxx:?
oceanbase::omt::ObPxPool::run1() at 0_cxx.cxx:?
oceanbase::omt::ObPxPool::run(long) at 0_cxx.cxx:?
oceanbase::lib::Thread::__th_start(void*) at 0_cxx.cxx:?
?? ??:0
?? ??:0

```

## 问题原因

在 OceanBase 数据库 V4.3.3 及之后版本，在 hash join 场景生成 join filter 时，会使用 Bloom Filter 后构建的优化，使用真实的行数来分配 Bloom Filter 的大小，这个功能需要在 join filter 算子内提前计算 hash join 的所有相关表达式，但是在表达式分配的时候，没有将这些表达式挪到 join filter 内部，导致出现了内存问题从而 core 掉。

快速判断方式：

1. 观察计划中 hash join 算子内关于是否有左表的表达式没有出现在 join filter 算子内。比如上面这个计划中，**2 号 hash join 中有一个 join key 左侧是 `cast(length(t1.c2), DECIMAL(20, 0))`，但是这个表达式没有分配在 3 号 join filter 中**。
 2. 堆栈中包含有 `join_filter_create_do_material` 和 `eval_vector` 相关信息。

   ```shell
   xxxx
   oceanbase::sql::ObExpr::eval_vector(oceanbase::sql::ObEvalCtx&, oceanbase::sql::ObBitVectorImpl const&, oceanbase::sql::EvalBound const&) const at ??:?
   oceanbase::sql::ObJoinFilterOp::join_filter_create_do_material
   xxxx

   ```

## 问题的风险及影响

中等。查询必须是满足 hash join 的等值条件中有一个计算表达式，且平均行长必须要够长。

## 影响租户

影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。

## 影响版本

OceanBase 数据库企业版 V4.3.3 GA（oceanbase-4.3.3.0-100000362024093001）及之后版本、V4.3.5 GA（oceanbase-4.3.5.0-100000122024123020）及之后版本。

## 解决方法

- 升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V4.3.3 BP1 Hotfix6（oceanbase-4.3.3.1-101060012025012322）、V4.3.3 BP1 Hotfix7（oceanbase-4.3.3.1-101070012025021915）、V4.3.5 GA Hotfix3（oceanbase-4.3.5.0-100030012025020717）、V4.3.5 GA Hotfix4（oceanbase-4.3.5.0-100040012025021921）、V4.3.5 GA Hotfix5（oceanbase-4.3.5.0-100050012025022422）、V4.3.5 GA Hotfix6（oceanbase-4.3.5.0-100060022025031922）、V4.3.5 GA Hotfix7（oceanbase-4.3.5.0-100070012025040810）、V4.3.5 GA Hotfix8（oceanbase-4.3.5.0-100080012025052715）、V4.3.5 GA Hotfix9（oceanbase-4.3.5.0-100090012025063017）、V4.3.5 GA Hotfix10（ooceanbase-4.3.5.0-100100032025071516）、V4.3.5 GA Hotfix11（oceanbase-4.3.5.0-100110012025072810）、V4.3.5 GA Hotfix12（oceanbase-4.3.5.0-100120012026011215）、V4.3.5 BP1（oceanbase-4.3.5.1-101000292025030623）。
 - 系统租户下，将集群配置项开关 `_preset_runtime_bloom_filter_size` 设置成 true。

  ```shell
  alter system set _preset_runtime_bloom_filter_size = true;

  ```

## 规避方式

系统租户下，将集群配置项开关 `_preset_runtime_bloom_filter_size` 设置成 true。

```

Previous

[OceanBase 数据库中执行 insert into select from 多表 join SQL 报错 -4016,Internal error 的原因和解决方法](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000001928612)

Next

[sql audit 内存满之后不刷新](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000004121103) ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
