我有一个大查询,在WHERE子句中我有类似的内容:
做点什么
或
做其他事情
(只有1个或)。。。
现在,如果我运行这个查询,SQL大约需要13秒才能完成。
如果我删除OR子句的第二部分,那么查询运行得非常快。
SQL不应该执行OR的第一部分吗?如果为true,不应该通过不查看OR的另一部分来完成查询吗?
为什么SQL同时考虑OR的两边?为什么不从第一个开始?
如果我删除OR子句的第二部分,那么查询运行得非常快。
有人能给我一些如何做到这一点的建议吗?
编辑-查询如下:
SELECT msc.ID,
msc.MediaCompanyID,
msc.AiringNumber,
msc.ClientNumber,
cl.ClientName,
MediaCompanyName,
CONVERT(VARCHAR, StandardDate, 101) StandardDateOnly,
CONVERT(DATETIME, CONVERT(VARCHAR, StandardDate, 101)) StandardDateOnlyDateType,
CONVERT(VARCHAR, StandardDate, 101) + ' ' + CONVERT(VARCHAR, StandardDate, 108) StandardDate,
CONVERT(VARCHAR, BroadcastDate, 101) + ' ' + CONVERT(VARCHAR, BroadcastDate, 108) BroadCastDate,
Station,
StationID,
msc.MediaCodeID,
msc.MediaCode,
MediaCodeDescr,
PhoneNumber,
DMA = CASE WHEN DMA IS NULL THEN MarketType
ELSE DMA
END,
msc.MarketID,
m.MarketDescr,
MIN(GrossCost) GrossCost,
MIN(ClientCost) ClientCost,
msc.CountryID,
CASE CountryName
WHEN 'UNITED STATES' THEN 'USA'
ELSE CountryName
END AS CountryName,
msc.LanguageID,
l.Language,
CASE IsConfirmed
WHEN 0 THEN 'No'
WHEN 1 THEN 'Yes'
END AS Teletrax
FROM dbo.MediaScheduleComplete msc
JOIN TVTraffic.dbo.Country c
ON msc.CountryID = c.CountryId
JOIN TVTraffic.dbo.Language l
ON msc.LanguageID = l.LanguageID
JOIN TVTraffic.dbo.Client cl
ON msc.ClientNumber = cl.ClientNumber
JOIN dbo.MediaCode mc
ON msc.MediaCodeID = mc.MediaCodeID
JOIN dbo.Market m
ON msc.MarketID = m.MarketID
LEFT JOIN TVTraffic.dbo.Offer o
ON mc.OfferID = o.OfferID
INNER JOIN @temp n
ON n.i = msc.ID
WHERE (
@MediaScheduleCompleteIDs IS NOT NULL
AND msc.ID IN (SELECT i
FROM TVTraffic.dbo.ufnListToSelectInt(@MediaScheduleCompleteIDs))
)
OR (
@MediaScheduleCompleteIDs IS NULL
AND (
StandardDate BETWEEN @from AND @to
AND (
msc.MediaCompanyID = @mediaCompanyID
OR @mediaCompanyID = 255
)
AND (
MarketType = @MarketType
OR @MarketType = ''
)
AND (
msc.ClientNumber = @clientID
OR @clientID = 0
)
-- and MediaCodeTypeID in (1,2,@SpecialTypeID)
AND (
msc.MediaCodeTypeID = @mediaCodeTypeID
OR @mediaCodeTypeID = 0
)
AND (
msc.CountryID = @CountryID
OR @CountryID = 0
)
AND (
msc.LanguageID = @LanguageID
OR @LanguageID = 0
)
AND (
mc.OfferID = @OfferID
OR @OfferID = 0
)
)
)
GROUP BY msc.ID,
msc.MediaCompanyID,
msc.AiringNumber,
msc.ClientNumber,
cl.ClientName,
MediaCompanyName,
StandardDate,
BroadcastDate,
Station,
StationID,
msc.MediaCodeID,
msc.MediaCode,
MediaCodeDescr,
PhoneNumber,
DMA,
msc.MarketID,
MarketDescr,
MarketType,
msc.CountryID,
CASE CountryName
WHEN 'UNITED STATES' THEN 'USA'
ELSE CountryName
END,
msc.LanguageID,
l.Language,
CASE IsConfirmed
WHEN 0 THEN 'No'
WHEN 1 THEN 'Yes'
END
ORDER BY ClientCost DESC,
StandardDate ASC
OR在SQL中的WHERE中不短路,因为它不是布尔运算。它的搜索条件是过滤掉行,这样它就可以返回满足任一侧的所有行
所以自然地,您必须找到OR两边的所有行才能返回它们。
所以当你有这样的东西时:
SELECT QUERY WHERE
[search condition 1] OR [search condition 2]
您必须始终找到满足搜索条件1或搜索条件2的所有行,并将它们作为结果集返回。
现在,如果你做了以下事情:
IF (1 = 1) OR ( 1 / 0 = 0)
PRINT 1
ELSE
PRINT 2
您将看到IF需要一个布尔结果语句,因此可以在某些类型的布尔检查上短路(适用于2012年及以后的版本,可能不完全向后兼容)
在另一个答案的基础上,SQL引擎的工作原理是它需要构建一个优化的执行计划,这就是它所遵循的执行计划。为此,它评估每个表达式,然后决定执行步骤。这属于汇编范围。只有当您使用动态SQL时,才会动态评估查询。但即便如此,在OR
声明的情况下,这是一个不同的故事,艾伦的回答很好地解释了这一点。
检查此文本http://sommarskog.se/dyn-search-2008.html
请尝试在查询末尾添加OPTION(RECOMPILE)。正如文章中所解释的,我猜查询优化器正在重用一个不适合您所做测试的查询计划。这样,每次调用sp时,查询计划都会重新计算,因此它会随着参数值的变化而变化。