首批通过分布式安全可靠测评,为关键业务系统打造
带多个子查询的 subplan filter 算子 PKEY 分布式计划查询结果错误
更新时间:2026-05-15 09:06
问题现象
示例。
obclient [SYS]> create table t1(c1 int,c2 int);
Query OK, 0 rows affected (0.076 sec)
obclient [SYS]> create table t2(c1 int,c2 int) partition by hash(c1) partitions 5;
Query OK, 0 rows affected (0.064 sec)
obclient [SYS]> create table t3(c1 int,c2 int) partition by hash(c1) partitions 5;
Query OK, 0 rows affected (0.041 sec)
obclient [SYS]> explain select (select t2.c1 from t2 where t2.c1 = t1.c1) as sql,
-> (select t3.c1 from t3 where t3.c1 = t1.c2) as sq2 from t1;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ==================================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
------------------------------------------------------------------
|0 |PX COORDINATOR | |100000 |397926985|
|1 | EXCHANGE OUT DISTR |:EX10001|100000 |397891626|
|2 | SUBPLAN FILTER | |100000 |397891626|
|3 | EXCHANGE IN DISTR | |100000 |74040 |
|4 | EXCHANGE OUT DISTR (PKEY) |:EX10000|100000 |38681 |
|5 | TABLE SCAN |T1 |100000 |38681 |
|6 | PX PARTITION ITERATOR | |4950 |1915 |
|7 | TABLE SCAN |T2 |4950 |1915 |
|8 | PX PARTITION ITERATOR | |4950 |1915 |
|9 | TABLE SCAN |T3 |4950 |1915 |
==================================================================
Outputs & filters:
-------------------------------------
0 - output([INTERNAL_FUNCTION(subquery(1), subquery(2))]), filter(nil)
1 - output([INTERNAL_FUNCTION(subquery(1), subquery(2))]), filter(nil), dop=1
2 - output([INTERNAL_FUNCTION(subquery(1), subquery(2))]), filter(nil),
exec_params_([T1.C1], [T1.C2]), onetime_exprs_(nil), init_plan_idxs_(nil)
3 - output([T1.C1], [T1.C2]), filter(nil)
4 - (#keys=1, [T1.C2]), output([T1.C1], [T1.C2]), filter(nil), is_single, dop=1
5 - output([T1.C1], [T1.C2]), filter(nil),
access([T1.C1], [T1.C2]), partitions(p0)
6 - output([T2.C1]), filter(nil)
7 - output([T2.C1]), filter(nil),
access([T2.C1]), partitions(p[0-4])
8 - output([T3.C1]), filter(nil)
9 - output([T3.C1]), filter(nil),
access([T3.C1]), partitions(p[0-4])
|
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.037 sec)
上述查询生成的分布式执行计划不正确。explain 展示查询的执行计划 7 号算子的计算是错误的。这个分布式查询的执行方式是将 T1 的数据按照 T1.C2 的取值进行重分区,然后再分别于 T2、T3 进行连接。
与 T3 的连接是正确的,因为 T1 按照 T1.C2 重分区之后,T1.C2 和 T3.C1 取值相同的数据会被分发到一起,对每一份数据按照 T1.C2 = T3.C1 进行连接是可以得到正确的结果的。
与 T2 的连接是错误的,由于 T1 和 T2 是按照 T1.C1 = T2.C1 进行连接,这要求:执行计划要把 T1.C1 和 T2.C1 取值相同的数据划分到一起;但是重分区的结果是,T1 按照 C2 切分;T2 按照 C1 切分,显然没有满足正确连接的要求。
触发生成以上错误执行计划需要满足以下几个条件:
所有子查询引用的表,分区模式一致;实际分区的物理分布完全相同。
所有子查询引用的表使用分区键和主查询进行连接。
以上连接条件中,需要引用主查询中不同的列。
子查询中不能存在聚合操作,rownum(通常为了保证子查询只返回一行,业务 SQL 会增加聚合函数,rownum 来控制子查询的输出行数,否则子查询返回多行时,查询执行会报错)。
关键诊断信息
触发条件
所有子查询引用的表,分区模式一致;实际分区的物理分布完全相同。
所有子查询引用的表使用分区键和主查询进行连接。
以上连接条件中,需要引用主查询中不同的列。
子查询中不能存在聚合操作,rownum(通常为了保证子查询只返回一行,业务 SQL 会增加聚合函数,rownum 来控制子查询的输出行数,否则子查询返回多行时,查询执行会报错)。
问题原因
针对子查询分布式场景计划优化引入的 BUG。
问题的风险及影响
子查询计算结果错误。
影响租户
影响 OceanBase 数据库中的 Oracle 租户和 MySQL 租户,对于 SYS 租户无影响。
影响版本
OceanBase 数据库企业版 V3.2.3 GA(oceanbase-3.2.3.0-20220419)及之后版本、V3.2.4 GA(oceanbase-3.2.4.0-100000072022102819)及之后版本、V4.2.1 GA(oceanbase-4.2.1.0-100000182023092722)及之后版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V3.2.3 BP11(oceanbase-3.2.3.3-111000032024070822)、V3.2.4 BP7(oceanbase-3.2.4.7-107000012023113010)、V4.2.1 BP2(oceanbase-4.2.1.2-102010012023120119)。
对子查询中使用的分区表的分区进行切主,避免多张分区表的物理分布完全一致,潜在的影响是这些分区表之间的执行计划会回退,增加一些网络交互的开销。
改写 SQL,对子查询的投影项增加一些聚合运算。例如 min/max。