【问题分类】SQL性能优化 / 执行计划问题
【关键词】filter、OR条件、索引失效、hash join失效、改写、UNION ALL
一、问题现象
当 SQL 语句的 WHERE 条件中使用 OR 关键字时,系统的查询计划可能会无法使用索引,也难以选择 hash join 作为连接策略,最终导致查询性能明显下降。
比如:
SELECT * FROM test_tab1. test_tab2
WHERE col1 = col4 OR col2 = col5;
上述语句在执行过程中不会走索引,也不会选择 hash join,而是变成了全表扫描 + 嵌套循环,性能十分低效。
二、问题验证案例
测试表准备
CREATE TABLE test_tab1 (col1 INT, col2 INT, col3 INT);
CREATE TABLE test_tab2 (col4 INT, col5 INT, col6 INT);
-- 批量插入数据
BEGIN
FOR i IN 1..10000 LOOP
INSERT INTO test_tab1 VALUES (i, i+1. i+2);
INSERT INTO test_tab2 VALUES (i, i+1. i+2);
END LOOP;
COMMIT;
END;
原始 SQL 查询及耗时
SELECT * FROM test_tab1. test_tab2
WHERE col1 = col4 OR col2 = col5;
-- 执行耗时:约 45 秒
改写后的查询语句
SELECT * FROM test_tab1. test_tab2
WHERE col1 = col4
UNION ALL
SELECT * FROM test_tab1. test_tab2
WHERE col1 <> col4 AND col2 = col5;
-- 执行耗时:约 0.4 秒
对比结论:
使用 OR 的写法 → 全表扫描,性能差;
改写为 UNION ALL → 可触发 hash join 与索引,性能提升近百倍。
三、问题根源分析
1.OR 条件导致过滤器无法下推到索引层
优化器面对 OR 会将其保留在 filter 逻辑中,无法将多个条件下推为索引扫描,因此整个表被迫全扫。
2.执行计划被阻断,无法使用 Hash Join
如果两个表 join 时存在 OR 条件,优化器也倾向放弃 hash join,从而进一步拖慢查询速度。
3.优化器未能自动重写为并集操作(CONCATENATION)
按照合理预期,OR 条件应该能拆成多个子查询再合并结果。但截至 2024 年 4 月,YashanDB 优化器暂未实现此自动改写逻辑。
四、解决方案与优化建议
改写 SQL 语句,手动拆分 OR 条件
将以下写法:
SELECT * FROM 表 WHERE col1 = 5 OR col2 = 5;
改写为:
SELECT * FROM 表 WHERE col1 = 5
UNION ALL
SELECT * FROM 表 WHERE col1 <> 5 AND col2 = 5;
这样更容易命中索引、触发 hash join,提升执行效率。
为参与条件的字段建立独立索引
例如:
CREATE UNIQUE INDEX idx_col1 ON test_tab1(col1);
CREATE UNIQUE INDEX idx_col2 ON test_tab1(col2);
在改写 SQL 后,这些索引才能被有效利用。
五、执行计划验证关键点
检查执行计划中是否出现 CONCATENATION 算子 → 表明已被优化器拆分执行;
检查 filter 是否仍存在复杂 OR 表达式 → 说明未能完全改写,仍阻碍索引使用;
评估是否使用 TABLE ACCESS BY INDEX ROWID 及 INDEX UNIQUE SCAN → 判定索引是否命中。
六、经验总结
建立索引 ≠ 能用上索引,SQL结构才是关键;
一条 SQL 中的 OR,往往是性能的“隐形杀手”;
改写为 UNION ALL,兼顾语义与性能,是更稳妥的方式;
未来版本中建议期待优化器自动支持 CONCATENATION 改写。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。