问题现象
在存在问题的 OceanBase 数据库版本中,当开启 SET GLOBAL _NLJ_BATCHING_ENABLED =true 同时用户的计划中存在 NESTED-LOOP JOIN 算子和 UNION ALL 正交相关,在执行时可能会报错 ERROR 4016 (HY000): Internal error。
示例如下。
创建表。
obclient [mysql]> CREATE TABLE t1(a int primary key, b int); Query OK, 0 rows affected (0.330 sec)obclient [mysql]> CREATE TABLE t2(a int primary key, b int); Query OK, 0 rows affected (0.389 sec)obclient [mysql]> CREATE TABLE t3(a int primary key, b int); Query OK, 0 rows affected (0.317 sec)插入数据。
obclient [mysql]> SET @rownum=0; ERT INTO t1 SELECT @rownum:=@rownum+1, @rownum FROM TABLE(generator(2000)) t;Query OK, 0 rows affected (0.007 sec)obclient [mysql]> INSERT INTO t1 SELECT @rownum:=@rownum+1, @rownum FROM TABLE(generator(2000)) t; Query OK, 2000 rows affected (0.291 sec) Records: 2000 Duplicates: 0 Warnings: 0obclient [mysql]> SET @rownum=0; INTO t2 SELECT @rownum:=@rownum+1, @rownum FROM TABLE(generator(2000)) t;Query OK, 0 rows affected (0.005 sec)obclient [mysql]> INSERT INTO t2 SELECT @rownum:=@rownum+1, @rownum FROM TABLE(generator(2000)) t; Query OK, 2000 rows affected (0.265 sec) Records: 2000 Duplicates: 0 Warnings: 0obclient [mysql]> SET @rownum=0; ERT INTO t3 SELECT @rownum:=@rownum+1, @rownum FROM TABLE(generator(2000)) t;Query OK, 0 rows affected (0.003 sec)obclient [mysql]> INSERT INTO t3 SELECT @rownum:=@rownum+1, @rownum FROM TABLE(generator(2000)) t; Query OK, 2000 rows affected (0.308 sec) Records: 2000 Duplicates: 0 Warnings: 0执行如下 SQL 语句。
obclient [mysql]> SELECT /*+use_nl(t1, t)*/ COUNT(1) FROM t1, (SELECT a FROM t2 UNION ALL SELECT a FROM t3) t WHERE t1.b>0 AND t1.a=t.a; ERROR 4016 (HY000): Internal error展示 SQL 语句执行计划。
obclient [mysql]> EXPLAIN SELECT /*+use_nl(t1, t)*/ COUNT(1) FROM t1, (SELECT a FROM t2 UNION ALL SELECT a FROM t3) t WHERE t1.b>0 AND t1.a=t.a;输出结果如下。
+------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------+ | ============================================================= | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------------- | | |0 |SCALAR GROUP BY | |1 |8301 | | | |1 |└─NESTED-LOOP JOIN | |200 |8297 | | | |2 | ├─TABLE FULL SCAN |t1 |200 |110 | | | |3 | └─SUBPLAN SCAN |t |2 |41 | | | |4 | └─UNION ALL | |2 |41 | | | |5 | ├─DISTRIBUTED TABLE GET|t2 |1 |21 | | | |6 | └─DISTRIBUTED TABLE GET|t3 |1 |21 | | | ============================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256 | | group(nil), agg_func([T_FUN_COUNT(*)]) | | 1 - output(nil), filter(nil), rowset=256 | | conds(nil), nl_params_([t1.a(:0)]), use_batch=true | | 2 - output([t1.a]), filter([t1.b > 0]), rowset=256 | | access([t1.a], [t1.b]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false], | | range_key([t1.a]), range(MIN ; MAX)always true | | 3 - output(nil), filter(nil), rowset=256 | | access(nil) | | 4 - output([UNION([1])]), filter(nil), rowset=256 | | 5 - output([t2.a]), filter(nil), rowset=256 | | access([GROUP_ID], [t2.a]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([t2.a]), range(MIN ; MAX)always true, | | range_cond([:0 = t2.a]) | | 6 - output([t3.a]), filter(nil), rowset=256 | | access([GROUP_ID], [t3.a]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([t3.a]), range(MIN ; MAX)always true, | | range_cond([:0 = t3.a]) | +------------------------------------------------------------------------------------+ 34 rows in set (0.116 sec)
问题诊断
事前巡检
计划中存在 NESTED-LOOP JOIN 算子和 UNION ALL / UNION 算子。

事后诊断
WDIAG [SQL.ENG] batch_fill_group_buffer (ob_group_join_buffer.cpp:650) [802752][T1032_L0_G0][T1032][xxxxx-xxxxx-xxxxx-xxxxx] [lt=6][errcode=-4016] rescan right failed(ret=-4016, ret="OB_ERR_UNEXPECTED")
WDIAG [SQL.ENG] group_get_left_batch (ob_nested_loop_join_op.cpp:766) [802752][T1032_L0_G0][T1032][xxxxx-xxxxx-xxxxx-xxxxx] [lt=7][errcode=-4016] batch fill group buffer failed(ret=-4016, ret="OB_ERR_UNEXPECTED")
WDIAG [SQL.ENG] get_left_batch (ob_nested_loop_join_op.cpp:616) [802752][T1032_L0_G0][T1032][xxxxx-xxxxx-xxxxx-xxxxx] [lt=6][errcode=-4016] fail to get left batch(ret=-4016)
通过日志关键词
grep 'rescan right failed' observer.log。找到报错的日志
rescan right failed同行的 trace_id。grep 'trace_id'如果日志与给出参照连续 3 条日志相同侧可以判断为相同问题。
问题原因
OceanBase 数据库实现逻辑中 NESTED-LOOP JOIN 执行优化的思路是减少执行过程中对数据的访问次数,因此需要使用到 BATCH RESCAN 的执行方式。和基础 NESTED-LOOP JOIN 算法不同,BATCH RESCAN 将驱动表的多次 RESCAN 操作合并成一次执行,BATCH RESCAN 要求参数带一个 Array 的标记。UNION 算子有两个 TABLE SCAN 子算子,由于一个实现的问题,第一个 TABLE SCAN 算子在第一批的时候污染了参数的标记。导致第二个 TABLE SCAN 拿到非法的参数,多个算子共用同一个参数的情况下,如果第一个算子切换后参数没有恢复,会影响后续共享该参数的算子的正常执行。所以有了非预期的 4016 报错。
问题的风险及影响
执行 SQL 报错 ERROR 4016 (HY000): Internal error 执行异常。
影响的版本
OceanBase 数据库 V4.2.1 GA Hotfix1 及之前版本,V4.1.0 BP4 Hotfix1 及之前版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库 V4.2.1 GA Hotfix2 (oceanbase-4.2.1.0-100020042023102310) 及之后版本。
规避方式
关闭 NLJ BATCH 优化。
obclient > SET GLOBAL _NLJ_BATCHING_ENABLED = false;
注意
关闭 NLJ BATCH 优化会存在性能回退。