OR改UNION后SQL查询性能飙升?求原因及非UNION优化方案
SQL查询性能优化:OR与UNION的性能差异分析
问题场景
我在调试一条关联Bookings和BookingPricings表的慢SQL,原查询通过OR条件分别过滤两张表的字段,执行耗时约4000ms;改写成UNION形式后,耗时骤降至约70ms,且输出结果完全一致。具体代码如下:
DECLARE @UserId UNIQUEIDENTIFIER = '0019813D-4379-400D-9423-56E1B98002CB' -- 原慢查询 SELECT * FROM Bookings LEFT JOIN BookingPricings ON Booking = Bookings.ID WHERE (BookingPricings.[Owner] in (@UserId) OR Bookings.MixedDealBroker in (@UserId)) -- 执行时间:约4000ms -- 优化后查询 SELECT * FROM Bookings LEFT JOIN BookingPricings ON Booking = Bookings.ID WHERE (BookingPricings.[Owner] in (@UserId)) UNION SELECT * FROM Bookings LEFT JOIN BookingPricings ON Booking = Bookings.ID WHERE (Bookings.MixedDealBroker in (@UserId)) -- 执行时间:约70ms
我原本以为SQL编译器能识别两种写法等价并自动选择最优执行计划,但实际并非如此。
背景说明
- 验证确认
IN(@UserId)和=@UserId对性能无影响; - 使用
JOIN或LEFT JOIN对性能无影响; - 两张表各含数十万条记录,过滤后仅返回约100条数据;
- 原慢查询会扫描两表所有行。
咨询问题
- 该性能差异产生的原因是什么?
- 不通过改写为UNION的方式,是否有其他可行的优化方案?
执行计划截图

问题解答
1. 性能差异的原因
SQL查询优化器在处理跨表的OR条件时,通常难以生成高效的执行计划。原查询中WHERE子句的OR连接了来自两个关联表的过滤条件(BookingPricings.[Owner]和Bookings.MixedDealBroker),优化器无法精准判断如何利用两张表上的索引快速定位数据,最终只能选择全表扫描遍历所有行,导致耗时极高。
而UNION写法将原查询拆分为两个独立子查询:第一个子查询仅过滤BookingPricings.[Owner],可利用BookingPricings表上[Owner]字段的索引快速筛选数据,再关联Bookings表;第二个子查询仅过滤Bookings.MixedDealBroker,可利用Bookings表上MixedDealBroker字段的索引定位数据,再关联BookingPricings表。两个子查询都能通过索引快速获取小数据集,最后通过UNION去重合并结果,整体执行效率大幅提升。
2. 其他优化方案
- 添加针对性复合索引:
- 给
Bookings表创建包含MixedDealBroker和关联字段ID的复合索引:CREATE INDEX IX_Bookings_MixedDealBroker ON Bookings(MixedDealBroker) INCLUDE(ID); - 给
BookingPricings表创建包含[Owner]和关联字段Booking的复合索引:CREATE INDEX IX_BookingPricings_Owner ON BookingPricings([Owner]) INCLUDE(Booking);
这类索引能帮助优化器直接通过索引筛选数据,避免全表扫描。
- 给
- 用
UNION ALL替代UNION(业务允许重复时):如果业务场景可以接受重复结果,将UNION改为UNION ALL,可省去去重开销,进一步提升性能。 - 强制指定索引(谨慎使用):通过
WITH(INDEX(索引名))(SQL Server)或FORCE INDEX(MySQL)等语法强制优化器使用指定索引,但该方式灵活性差,后续表结构变化可能导致失效,需谨慎使用。
内容的提问来源于stack exchange,提问作者Brondahl
相关产品推荐
相关产品推荐

