问题现象
业务集群从 OceanBase 数据库 V4.2.5 BP2 Hotfix3 版本升级到 V4.2.5 BP3 Hotfix3 版本后,执行计划发生了改变,升级前 SQL 中的谓词 OR 能正常转成 UNION ALL,升级后新版本无法 OR 展开转成 UNION ALL 的计划。 升级前老版本 V4.2.5 BP2 Hotfix3 执行 5ms,升级后执行几个小时也无法完成,且手动指定 /*+ USE_CONCAT */ Hint 也执行不出来,业务 SQL 中使用了视图、复制表、UDF。
SELECT 'Y' FROM xxx A, xxx B WHERE A.xxxNO = B.xxxNO AND (A.APPxxx = 'xxx' OR B.INxxx = 'xxx' OR B.JxxxNO = 'xxx' ) AND ROWNUM = 1;
升级前的计划:

升级后的计划:

关键诊断信息
触发条件
SQL 中有 OR 的谓词条件并且使用了自定义函数 UDF 没有显式指定 DETERMINISTIC。
事前巡检
如果计划能
OR展开侧计划 Outline Data 信息会包含/*+ USE_CONCAT */Hint,如果没有/*+ USE_CONCAT */Hint 同时有UNION ALL算子计划可能没展开。
检查计划中 Filter 使用使用了自定义函数是否定义显式指定
DETERMINISTIC或者使用了不确定性的函数。
问题原因
OceanBase 数据库 V4.2.5 BP3 之前的版本,如果用户 SQL 使用了自定义函数 UDF,不会进行确定性检查,OR 展开之后会得到一个潜在更好的计划,但遇到边界条件的场景,UDF 行为不具备确定性的话,结果就会错,所以 V4.2.5 BP3 增加了 UDF 的确定性检查,只有标记了确定性的 UDF,才可以尝试 OR 展开。这个业务是创建了一个 UDF,这个 UDF 实际行为是确定性的,但没有带 DETERMINISTIC 的标记,必须显式指定 DETERMINISTIC,UDF 有标记后,然后优化器就可以认为这个 UDF 就是一个是确定的 const expr 对其做 OR 展开或者其他优化。
补充说明:
如果一个自定义函数 UDF 总是对相同的输入参数产生相同的结果,那么它被认为是确定性的,否则就被认为是不确定性的。如果 UDF 定义中既没有给出 DETERMINISTIC 也没有给出 NOT DETERMINISTIC,则默认为 NOT DETERMINISTIC。要声明函数是确定性的,必须显式指定 DETERMINISTIC。
-- 如何定义一个 DETERMINISTIC 函数
DELIMITER //
CREATE FUNCTION add_numbers(a INT, b INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE result INT;
SET result = a + b;
RETURN result;
END //
DELIMITER;
-- 非 DETERMINISTIC 函数的示例
DELIMITER //
CREATE FUNCTION get_current_time()
RETURNS TIME
NOT DETERMINISTIC
BEGIN
DECLARE current_time TIME;
SET current_time = CURTIME();
RETURN current_time;
END //
DELIMITER;
问题的风险及影响
OceanBase 数据库 V4.2.5 BP3 版本增加了 UDF 的确定性检查会导致没显式指定 DETERMINISTIC 的 UDF 无法 OR 展开,计划等同于全表扫描执行慢。
适用版本
OceanBase 数据库 V4.2.5 BP3(oceanbase-4.2.5.3-103000142025033110)之前的版本。
解决方法与规避方式
SQL 中有 OR 的谓词条件并且使用了自定义函数 UDF 必要显式指定 DETERMINISTIC,业务也需要规避使用不确定性的 UDF 函数。