如何在SQL Server中的查询中,在WHERE子句中强制OR子句覆盖另一个子句



我有一个大查询,在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时,查询计划都会重新计算,因此它会随着参数值的变化而变化。

最新更新