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