You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL中OR条件下为何触发全表扫描而非索引查找?能否无需UNION优化?

跨表OR条件与UNION查询的执行计划差异解析

一、为什么OR条件会触发全表扫描

  1. 跨表OR的逻辑限制
    你的OR条件分别属于关联的两张表:hdr.SalesOrderID = 43659 针对主表,dtl.SalesOrderDetailID = 43659 针对子表。SQL优化器的索引查找逻辑是基于单表维度的,它无法同时利用两张表的索引构建高效执行计划——JOIN本身已经在关联两张表,跨表OR相当于要求“要么主表ID匹配,要么子表ID匹配”,这种复合逻辑无法直接映射到现有索引的查找路径,最终优化器只能选择全表扫描两张表后再过滤符合条件的行。

  2. 成本估算的选择
    优化器会对比不同执行计划的成本。当跨表OR条件出现时,优化器可能认为:拆解条件、分别走索引再合并结果的成本,比直接全表扫描更高(尤其是表数据量较小时),因此不会主动将OR查询优化为类似UNION的索引查找逻辑。

二、无需改写为UNION的替代方案

可以通过先筛选目标ID再关联的方式,让优化器分别利用两张表的索引,避免全表扫描:

SELECT DISTINCT hdr.*, dtl.*
FROM (
    -- 索引查找主表符合条件的订单ID
    SELECT SalesOrderID FROM [AdventureWorks2022].[Sales].[SalesOrderHeader] WHERE SalesOrderID = 43659
    UNION ALL
    -- 索引查找子表目标行对应的订单ID
    SELECT dtl.SalesOrderID FROM [AdventureWorks2022].[Sales].[SalesOrderDetail] dtl WHERE dtl.SalesOrderDetailID = 43659
) AS filtered_ids
JOIN [AdventureWorks2022].[Sales].[SalesOrderHeader] hdr ON hdr.SalesOrderID = filtered_ids.SalesOrderID
JOIN [AdventureWorks2022].[Sales].[SalesOrderDetail] dtl ON hdr.SalesOrderID = dtl.SalesOrderID

这个写法的核心是先通过两个独立的索引查找得到所有符合条件的SalesOrderID,再用这些ID关联两张表,全程都会利用索引;DISTINCT用于避免重复行,和原UNION的去重效果一致。如果能确认两个条件不会返回重复行,可将DISTINCT换成UNION ALL进一步提升性能。

内容的提问来源于stack exchange,提问作者J. Moore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 12:56:11