当前位置: 首页 > news >正文

SQL优化--OR

优化 SQL 中的 OR 条件是一个非常常见的性能调优问题。OR 操作符经常会导致性能下降,因为它使得数据库优化器难以高效地使用索引。

下面我将从浅入深地为你讲解优化 OR 的多种策略,并附上示例。

为什么 OR 性能往往较差?

在简单的 WHERE 子句中,每个条件通常可以利用自己的索引。但是,当使用 OR 连接两个针对不同列的条件时,数据库可能无法同时使用两个索引(在旧版本或某些情况下),从而导致全表扫描。


优化策略一览

以下是优化 OR 条件的几种核心方法,你可以根据实际情况选择:

  1. 使用 UNION / UNION ALL 拆分查询 (最有效、最常用的方法)

  2. 使用 IN 操作符 (当 OR 作用于同一字段时)

  3. 使用多列索引 (针对特定的 OR 条件组合)

  4. 使用 CASE 语句和函数索引 (较为复杂,特定场景下使用)

  5. 重构逻辑:使用 AND 和 OR 的组合


方法一:使用 UNION 或 UNION ALL (首选方案)

这是优化不同列上 OR 条件的最强大和最可靠的方法。它的思路是将一个包含 OR 的查询拆分成多个独立的、都能高效使用索引的查询,然后将结果合并。

优化前:

SELECT *
FROM orders
WHERE status = 'shipped' OR customer_id = 123;

假设 status 和 customer_id 上分别有索引,但这个查询可能只能使用其中一个索引,或者直接进行全表扫描。

优化后:

SELECT * FROM orders WHERE status = 'shipped'
UNION ALL
SELECT * FROM orders WHERE customer_id = 123;
  • UNION ALL: 比 UNION 更快,因为它不去重。如果你的两个查询条件绝无可能重叠,或者你允许重复数据,一定要用 UNION ALL

  • UNION: 会去除重复的行,开销更大。只有在可能出现重复记录且你需要去重时才使用它。

为什么更优?
现在每个 SELECT 语句都可以充分利用自己的索引:

  • 第一个查询使用 idx_status 索引。

  • 第二个查询使用 idx_customer_id 索引。
    数据库最终将两个高效的独立查询结果合并起来,通常比扫描整张表要快得多。


方法二:使用 IN 操作符 (针对同一字段)

如果 OR 是用在同一个字段上,将其改为 IN 操作符是更简洁的做法。数据库优化器对 IN 的处理通常非常高效。

优化前:

SELECT *
FROM products
WHERE category_id = 1 OR category_id = 2 OR category_id = 7;

优化后:

SELECT *
FROM products
WHERE category_id IN (1, 2, 7);

这两句在逻辑上完全等价,但 IN 的写法更简洁,并且数据库优化器可以非常完美地利用 category_id 上的索引。

注意IN 只能用于优化同一字段的 OR 条件。对于不同字段的 ORIN 无能为力。


方法三:使用多列索引 (覆盖索引)

如果你的 OR 条件查询是某个高频且固定的模式,可以考虑创建一个覆盖这些列的索引。

例如,对于查询 WHERE a = 1 OR b = 2,可以创建一个索引 on (a, b)

但是要注意:多列索引对于 WHERE a = 1 AND b = 2 非常有效,但对于 OR,效果可能不如 UNION。有些数据库(如 MySQL)在某些情况下可以对这种查询使用索引合并(Index Merge),即同时使用 idx_a 和 idx_b 两个索引,然后合并结果,但这并不总是发生,而且效率通常不如 UNION 方案稳定。

所以,通常建议将 UNION 作为首选,创建多列索引更多是为了优化 AND 条件。


方法四:重构逻辑(巧用德摩根定律)

有时候,你可以通过应用逻辑定律来重写查询,避免使用 OR

根据德摩根定律:NOT (A AND B) = (NOT A) OR (NOT B)

我们可以反过来运用它。例如,一个复杂的查询可能被重写:

优化前:

SELECT *
FROM users
WHERE (status = 'active' AND last_login > '2023-01-01')OR (status = 'inactive' AND signup_source = 'google');

这个查询可能不太好优化。

有时可以尝试重写为:

SELECT *
FROM users
WHERE status = 'active' AND last_login > '2023-01-01'
UNION ALL
SELECT *
FROM users
WHERE status = 'inactive' AND signup_source = 'google';

(看,又回到了我们万能的方法一)


总结与建议

场景推荐优化方法示例
OR 作用于不同字段UNION ALL / UNIONWHERE a=1 OR b=2 -> 拆成两个 SELECT 用 UNION ALL 连接
OR 作用于同一字段INWHERE id=1 OR id=2 OR id=3 -> WHERE id IN (1,2,3)
固定模式的高频查询考虑创建多列索引对 (a, b) 建索引,但需测试效果是否优于 UNION
复杂条件混合重构逻辑 + UNION将复杂条件拆解,分别优化,最后合并

最终建议:

  1. 首先检查执行计划: 在任何优化前后,都使用 EXPLAIN(MySQL/PostgreSQL)或 EXPLAIN PLAN(Oracle)来查看数据库的实际执行路径,这是性能调优的金科玉律。

  2. 首选 UNION ALL: 对于不同字段的 OR 条件,UNION ALL 在绝大多数情况下都是最佳选择。记得确认是否可以用 UNION ALL 代替 UNION

  3. 索引是基础: 确保 OR 条件中涉及的每个字段都有合适的索引。没有索引,任何优化技巧都效果有限。

  4. 保持简洁: 对于同一字段的多个 OR,果断改用 IN

通过结合以上策略和分析执行计划,可以有效地解决大多数由 OR 引起的 SQL 性能问题。

http://www.dtcms.com/a/356515.html

相关文章:

  • springboot中循环依赖的解决方法-使用反射
  • linux mysql数据备份
  • 零基础上手:Cursor + MCP 爬取 YouTube 视频数据
  • 政策技术双轮驱动 | 新一代工业软件供需对接会·顺德站成功举办
  • 深入解析Nginx核心模块
  • npm使用的环境变量及其用法
  • 专业的储存数据的结构:数据库
  • 【开题答辩全过程】以 基于Python的美食点评系统为例,包含答辩的问题和答案
  • iOS混淆工具实战 电商类 App 的数据与交易安全防护
  • Lambda 表达式在 PyQt/PySide 中的应用
  • Python OpenCV图像处理与深度学习:Python OpenCV入门-图像处理基础
  • 什么是 MySQL的主从同步机制?它是如何实现的?
  • 交互设计 | 无人机控制系统的 UI 设计:从人机交互到任务管理
  • Word - Word 查找文本中的特定内容
  • 宜春城区光纤铺设及接口实地调研
  • 宜春城区SDH网图分析
  • 设计模式Books Reading
  • 计算机视觉----opencv(图像轮毂绘制(大小选择,排序,外接图形绘制),轮廓的近似,模板的匹配)
  • mybatis.xml直接读取配置文件(application.yml)中的数据
  • java数据结构--排序
  • 工业相机的类型及不同类型的应用
  • Python 实战:内网渗透中的信息收集自动化脚本(5)
  • 2025.8.29总结
  • MFC视图中绘制图形缩放和滚动条的处理
  • C/C++---预定义常量
  • Fast-LIVO2算法与其他激光雷达-惯性-视觉里程计算法相比有何优势?
  • 【LeetCode 热题 100】62. 不同路径——(解法二)递推
  • Spring Security 传统 web 开发场景下开启 CSRF 防御原理与源码解析
  • “我店 + RWA”来袭:重构商业价值,解锁消费投资新密码
  • 大模型入门学习微调实战:基于PyTorch和Hugging Face电影评价情感分析模型微调全流程(附完整代码)手把手教你做