优化 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.pswp.cn/news/920500.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920500.shtml
英文地址,请注明出处:http://en.pswp.cn/news/920500.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java试题-选择题(21)

Java试题-选择题(21) 题目 有关线程的叙述正确的是 ? A:可以获得对任何对象的互斥锁定 B:通过继承Thread类或实现Runnable接口,可以获得对类中方法的互斥锁定 C:线程通过使用synchronized关键字可获得对象的互斥锁定 D:线程调度算法是平台独立的 下面有关forward和re…

预测模型及超参数:3.集成学习:[1]LightGBM

想象你是一位乐队指挥,你的任务是协调乐队中的每位音乐家,以演奏出一场完美的音乐会。每位音乐家(即决策树)擅长不同的乐器或乐章。在指挥过程中,你通过调节各位音乐家演奏的强度(模型参数)&…

Jetson进行旋转目标检测推理实现大疆无人机飞行控制

源码结构 大疆PSDK源码地址: https://github.com/dji-sdk/Payload-SDK其目录结构如下: Payload-SDK-master ├── CMakeLists.txt ├── doc │ ├── dji_sdk_code_style │ └── simple_model ├── EULA.txt ├── LICENSE.txt ├── psd…

阿里云百炼智能体连接云数据库实践(DMS MCP)

这篇文章主要是通过使用阿里云的百炼智能体与阿里云的serverless来实现数据库的操作 欢迎一起交流!! 首先,当然是选择自己需要的数据库啦 在阿里云控制台选择产品 - > 数据库 - > 数据管理DMS进来的界面如下所示 第一次进来的时候是…

某商店JS混淆补环境与纯算逆向分析

文章目录1. 写在前面2. 接口分析3. 补环境分析4. 纯算法还原【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并…

如何安装 mysql-installer-community-8.0.21.0.tar.gz(Linux 详细教程附安装包下载)​

这是一个 ​Linux 下 MySQL 8.0.21 的压缩安装包,虽然名字里有 installer,但它其实就是一个压缩好的二进制安装包,不是 Windows 那种图形化安装程序。 一、准备工作 确保你已经有: Linux 系统(比如 Ubuntu、CentOS、…

IDEA-琴澳研究中心及学术联盟启动,产研协同赋能区域发展

8月30日,IDEA-琴澳中心主导研发的Smaray渲染引擎将发布可免费下载的Tech Preview(技术预览版)。本次发布标志着粤港澳大湾区在政产研协同创新实现成果落地,也是产业“人工智能”的探索迈进。Smaray是国内首个公开服务的、AI驱动的…

如何备份 TECNO 手机上的短信

许多 TECNO 用户都在寻找方法,以防止因手机损坏、被盗或恢复出厂设置而导致重要对话意外丢失,确保在需要时能够访问他们的数据。还有些人希望在释放设备存储空间的同时,仍然保留旧消息的副本以供日后参考。如果你一直在寻找“备份 TECNO 短信…

OpenAI Sora深度解析:AI视频生成技术如何重塑广告电商行业?影业合作已落地

最近刷到一条超震撼的视频:咖啡杯从桌角滑落,在空中转了半圈居然自己弹回桌面,牛奶一滴没洒。你猜怎么着?这居然是AI生成的,就是OpenAI那个叫Sora的工具做的。是不是觉得有点不可思议?现在这技术已经能做到…

力扣p1011在D天送达包裹的能力 详解

题目如下:代码如下,先看代码,再看思路:注意,从check函数下方的left处看,我认为难点在于以啥来二分,都说求啥拿啥分,但实际无从下手,关键在于如何寻找边界,此处…

React Three Fiber

下面,我们来系统的梳理关于 React Three Fiber:WebGL 与 React 的基本知识点: 一、React Three Fiber 核心概念 1.1 什么是 React Three Fiber? React Three Fiber(R3F)是一个用于 Three.js 的 React 渲染…

YARN架构解析:深入理解Hadoop资源管理核心

YARN架构解析:深入理解Hadoop资源管理核心 🌟 你好,我是 励志成为糕手 ! 🌌 在代码的宇宙中,我是那个追逐优雅与性能的星际旅人。 ✨ 每一行代码都是我种下的星光,在逻辑的土壤里生长成璀璨的银…

爬虫代理的核心作用、分类及使用要点

在数据采集场景中,爬虫代理作为“中间传输节点”,通过转发爬虫请求、隐藏真实IP地址,解决传统爬虫面临的诸多限制,其核心价值体现在三个方面:突破IP封锁与访问限制:多数网站会对高频请求的IP进行封锁&#…

EXCEL开发之路(三)sheets梯形样式设计—仙盟创梦IDE

在蔬菜批发行业,高效的信息管理与操作便捷性对于业务的顺畅开展至关重要。梯形 Nav(导航栏)切换这一设计,看似只是界面交互的小细节,实则在提升用户体验、优化业务流程等方面有着不可忽视的意义,对于初学者…

Unity游戏打包——iOS打包pod的重装和使用

本文由 NRatel 历史笔记整理而来,如有错误欢迎指正。 一、重装 pod 和使用 1、下载安装 rvm curl -L get.rvm.io | bash -s stable 2、使环境变量生效 (zsh) source ~/.zshrc source ~/.profile 3、查看rvm版本 rvm -v 4、重装ruby 关闭mac sip(可能需…

AWS OpenSearch 可观测最佳实践

AWS OpenSearch 介绍 OpenSearch 是一种全面开源搜索和分析引擎,使用案例包括日志分析、实时应用程序监控、点击流分析等。Amazon OpenSearch Service 是一项托管服务,让用户能够在 AWS 云中轻松部署、运行并扩展 OpenSearch 集群。 观测云 观测云是一…

HTML5七夕节网站源码

一,网站概述 本七夕节主题网站采用HTML5、CSS3与JavaScript技术栈构建,响应式设计适配多终端设备,通过模块化开发实现丰富交互体验。以下从架构设计、功能实现和视觉效果三方面概述: 1.1、架构设计 采用单页应用(SPA)架构&…

以技术赋能强化消费者信任,助推餐饮服务质量提质增效的明厨亮灶开源了

AI 视频监控平台简介 AI 视频监控平台是一款兼具强大功能与便捷操作的实时算法视频监控系统。其核心愿景在于打破各大芯片厂商间的技术壁垒,省去冗余重复的适配流程,构建 “芯片 - 算法 - 应用” 的全流程组合体系。这一体系可帮助企业级应用降低约 95%…

【NJU-OS-JYY笔记】操作系统:设计与实现

1. 绪论 1.1. 程序的执行与状态机 在计算机科学中,任何程序都可以被抽象为一个状态机,无论是我们熟知的日常工具(LibreOffice,Chrome)还是开发工具(IDE,GCC,GDB)&#…

GaussDB 修改schema属主时报:must be member of role “dtest“

1 问题现象schema的属主为root,客户需要修改对应的业务用户,在使用root用户登入postgres库时修改schema属主时报:ERROR:dn_6007_6008_6009:must be member of role "dtest"执行命令为:alter schema dtest owner to dtes…