问题现象
存在 (c1) 的索引,SQL 过滤条件中存在如下形式的过滤谓词 c1 in (?,?) or c1 < ? or c1 > ?。且从 IN 值中去掉满足 c1 < ? or c1 > ? 的值后只剩 1 个 IN 值。这个场景下会给 TABLE SCAN 算子错误的打上 GET 标记导致执行结果出错。
举例: c1 IN (7,10) OR c1 < 3 or c1 > 10,等价于c1 in (7) or c1 < 3 or c1 > 10。
================================================
|ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|
------------------------------------------------
|0 |TABLE GET |t1 |4 |2 | <-- 这个不是 Table Get 的。
================================================
Outputs & filters:
-------------------------------------
0 - output([t1.pk]), filter(nil), rowset=256
access([t1.pk]), partitions(p0)
is_index_back=false, is_global_index=false,
range_key([t1.pk]), range[7 ; 7], (NULL ; 3), [10 ; MAX),
range_cond([(T_OP_OR, t1.pk IN (7, 10), t1.pk < 3, t1.pk > 10)])
关键诊断信息
触发条件
存在 (c1) 的索引,SQL过滤条件中存在如下形式的过滤谓词 c1 in (?,?) or c1 < ? or c1 > ?。且从 IN 值中去掉满足 c1 < ? or c1 > ? 的值后只剩 1 个 IN 值。
事前巡检
检查是否存在上述形式的谓词和对应的索引。
事后诊断
explain 计划,检查生成的 range 中是否缺失了 C2 指定的值。
问题原因
IN 优化引入的 BUG。
问题的风险及影响
SQL 执行结果出错。
影响租户
影响 OceanBase 数据库中的 SYS 租户和 MySQL 租户,对于 Oracle 租户无影响。
影响版本
OceanBase 数据库企业版本 V3.2.3 BP6(oceanbase-3.2.3.3-106000102022111521)及之后版本、V3.2.4 GA(oceanbase-3.2.4.0-100000072022102819)及之后版本、V4.1.0 GA(oceanbase-4.1.0.0-100001122023040322)及之后版本。
解决方法
解决方法一:、
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V3.2.3 BP9(oceanbase-3.2.3.3-109000182023071410)及之后版本、V3.2.4 BP3(oceanbase-3.2.4.3-103000032023041816)及之后版本、V4.1.0 BP2(oceanbase-4.1.0.1-102000042023061309)及之后版本。
解决方法二:
将 IN 表达式改成等价的 OR 表达式,例如
c1 in ('1','2') => (c1 = '1' or c1 = '2')。通过 Hint 禁止走包含 IN 表达式所在列的索引,例如
select /+full(t1)/...。在 IN 表达式后面加个
is true(适用于命中主键索引的场景),例如c1 in ('1','2') is true。如果出现问题的 OceanBase 数据库版本为以下版本或更高,可以通过隐藏配置项
_enable_in_range_optimization关闭 IN 优化。OceanBase 数据库企业版 V3.2.3 BP8 Hotfix5(oceanbase-3.2.3.3-108050012023070409)及之后版本。
OceanBase 数据库企业版 V3.2.4 BP4(oceanbase-3.2.4.4-104000052023062021)及之后版本。
OceanBase 数据库企业版 V4.1.0 BP2(oceanbase-4.1.0.1-102000042023061309)及之后版本。
规避方式
无。
相关文档
关于 IN 优化引入的其他正确性问题,参见:IN 优化引入的正确性问题一、IN 优化引入的正确性问题二、IN 优化引入的正确性问题四。