优化NOT IN和OR查询的核心是避免全表扫描,优先使用LEFT JOIN ... IS NULL或NOT EXISTS替代NOT IN,将OR拆分为UNION ALL,并为各分支条件建立合适索引,结合执行计划分析确保索引有效利用。

优化包含
NOT IN
OR
NOT IN
LEFT JOIN ... IS NULL
NOT EXISTS
OR
UNION ALL
EXISTS
在我看来,处理这类查询,首先要做的就是放下对现有SQL语句的“情感”,用一种批判性的眼光去审视它。很多时候,我们写SQL是基于业务逻辑的直观表达,而不是基于数据库性能的考量。
NOT IN
OR
我通常会从以下几个方面入手:
NOT IN
OR
NOT IN
NOT IN
NULL
NOT IN
LEFT JOIN ... IS NULL
NOT EXISTS
OR
OR
SELECT
UNION ALL
EXISTS
WHERE
JOIN
ORDER BY
OR
NOT IN
OR
我的观点是,优化查询是一个迭代的过程。先尝试最直接的替换和重构,然后再次检查执行计划,看看是否有所改善。如果效果不明显,再深入分析,考虑更复杂的索引或设计方案。
NOT IN
首先,
NOT IN
NOT IN
NULL
NOT IN
UNKNOWN
NULL
其次,
NOT IN
NOT IN
IN
基于这些痛点,我强烈建议采用以下两种更优的替代方案:
LEFT JOIN ... WHERE IS NULL
NULL
NULL
-- 原始的 NOT IN 查询 SELECT a.* FROM table_a a WHERE a.id NOT IN (SELECT b.a_id FROM table_b b WHERE b.status = 'inactive'); -- 优化后的 LEFT JOIN ... IS NULL SELECT a.* FROM table_a a LEFT JOIN (SELECT DISTINCT b.a_id FROM table_b b WHERE b.status = 'inactive') AS excluded_ids ON a.id = excluded_ids.a_id WHERE excluded_ids.a_id IS NULL;
这里我特意在子查询中加了
DISTINCT
LEFT JOIN
a.id
b.a_id
NOT EXISTS
NOT EXISTS
NOT EXISTS
NOT IN
NOT EXISTS
NULL
NOT IN
NULL
-- 原始的 NOT IN 查询 (同上) SELECT a.* FROM table_a a WHERE a.id NOT IN (SELECT b.a_id FROM table_b b WHERE b.status = 'inactive'); -- 优化后的 NOT EXISTS SELECT a.* FROM table_a a WHERE NOT EXISTS (SELECT 1 FROM table_b b WHERE b.a_id = a.id AND b.status = 'inactive');
我个人更偏爱
LEFT JOIN ... IS NULL
NOT EXISTS
包含多个
OR
OR
OR
OR
我的经验是,重构这类查询的关键在于“分而治之”和“化繁为简”。
拆分为UNION ALL
OR
SELECT
UNION ALL
SELECT
OR
-- 原始的包含多个 OR 条件的查询 SELECT * FROM orders WHERE (customer_id = 101 AND status = 'pending') OR (order_date < '2023-01-01' AND total_amount > 1000) OR (region = 'North' AND delivery_method = 'express'); -- 优化后的 UNION ALL SELECT * FROM orders WHERE customer_id = 101 AND status = 'pending' UNION ALL SELECT * FROM orders WHERE order_date < '2023-01-01' AND total_amount > 1000 UNION ALL SELECT * FROM orders WHERE region = 'North' AND delivery_method = 'express';
这里需要注意,
UNION ALL
UNION
UNION
UNION ALL
利用EXISTS
IN
OR
EXISTS
IN
-- 假设我们想找到在某个特定时间段内,有任意一个子订单满足某种条件的父订单
-- 原始的复杂 OR (可能需要 JOIN)
SELECT p.*
FROM parent_orders p
JOIN child_orders c ON p.id = c.parent_id
WHERE (c.status = 'returned' AND c.return_date > '2023-06-01')
   OR (c.quantity > 100 AND c.product_category = 'electronics');
-- 优化后的 EXISTS
SELECT p.*
FROM parent_orders p
WHERE EXISTS (SELECT 1 FROM child_orders c
              WHERE c.parent_id = p.id
                AND (c.status = 'returned' AND c.return_date > '2023-06-01'
                     OR c.quantity > 100 AND c.product_category = 'electronics'));这里虽然子查询内部仍然有
OR
EXISTS
child_orders
OR
IN
WHERE status IN ('pending', 'processing', 'shipped')创建复合索引或函数索引:在某些特定情况下,如果
OR
CREATE INDEX idx_status_region ON orders (status, region);
OR
OR
最终,选择哪种重构方式,都需要结合实际的业务场景、数据分布、数据库类型和最重要的——执行计划来决定。没有一劳永逸的方案,只有最适合当前问题的解决方案。
在我看来,索引策略和执行计划分析就像是医生手中的X光片和处方药。你不能只开药(建索引)而不看病灶(分析执行计划),也不能只看病灶而不对症下药。它们是紧密结合、缺一不可的。
深入理解执行计划: 这是我每次遇到性能问题时,首先会做的事情。执行计划能告诉你数据库“思考”了什么,它打算如何执行你的查询。
Full Table Scan
Full Index Scan
Range Scan
Index Seek
Nested Loops
Hash Join
Merge Join
Using temporary
Using filesort
对于
NOT IN
OR
NOT IN
OR
制定精准的索引策略: 索引不是越多越好,也不是越大越好。错误的索引甚至会降低写入性能。我的索引策略通常遵循以下原则:
SELECT count(*)
SELECT id, status FROM orders WHERE status = 'pending'
orders
(status, id)
WHERE
WHERE customer_id = ? AND order_date > ?
(customer_id, order_date)
OR
WHERE
YEAR(order_date)
(a, b, c)
(a)
(a, b)
a
a, b
针对
NOT IN
OR
NOT IN
NOT EXISTS
LEFT JOIN ... IS NULL
a.id
b.a_id
OR
UNION ALL
UNION ALL
WHERE
OR
OR
UNION ALL
总的来说,优化是一个不断试错和学习的过程。我常常会建立一个假设(比如“我觉得这里加个索引会快”),然后通过修改SQL或添加索引,再运行执行计划,对比前后差异,最终找到最优解。这个过程需要耐心,也需要对数据库原理有扎实的理解。
以上就是如何优化包含NOT IN、、OR等操作的查询?的详细内容,更多请关注php中文网其它相关文章!
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号