写点什么

YashanDB 知识库|SQL 中用了 OR,怎么反而性能下降了? 该不该改写?

作者:数据库砖家
  • 2025-04-21
    广东
  • 本文字数:1198 字

    阅读完需:约 4 分钟

【问题分类】SQL 性能优化 / 执行计划问题

【关键词】filter、OR 条件、索引失效、hash join 失效、改写、UNION ALL

一、问题现象

当 SQL 语句的 WHERE 条件中使用 OR 关键字时,系统的查询计划可能会无法使用索引,也难以选择 hash join 作为连接策略,最终导致查询性能明显下降。

比如:

SELECT * FROM test_tab1. test_tab2WHERE 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);
复制代码

-- 批量插入数据

BEGINFOR i IN 1..10000 LOOPINSERT 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_tab2WHERE col1 = col4 OR col2 = col5;-- 执行耗时:约 45 秒
复制代码

改写后的查询语句

SELECT * FROM test_tab1. test_tab2WHERE col1 = col4UNION ALLSELECT * FROM test_tab1. test_tab2WHERE 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 = 5UNION ALLSELECT * 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 改写。

用户头像

还未添加个人签名 2025-04-09 加入

还未添加个人简介

评论

发布
暂无评论
YashanDB知识库|SQL 中用了 OR,怎么反而性能下降了?该不该改写?_数据库_数据库砖家_InfoQ写作社区