如何在SQL Server的查询中的WHERE子句中强制使用OR子句?

时间:2015-02-27 01:27:04

标签: sql sql-server where

我有一个大查询,在WHERE子句中我有类似的东西:

做点什么

OR

做别的事情

(仅1 OR)......

现在,如果我运行此查询,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

3 个答案:

答案 0 :(得分:1)

OR在SQL中的WHERE中没有短路,因为它不是布尔操作。搜索条件是过滤掉行,以便它可以返回所有行,这些行可以满足任何一方的要求 所以很自然地你必须找到OR两边的所有行才能返回它们。

所以当你有类似的东西时:

SELECT QUERY WHERE
[search condition 1] OR [search condition 2]

您将始终必须找到满足搜索条件1 OR 搜索条件2的所有行,并将其作为结果集返回。

现在,如果您执行了以下操作:

IF (1 = 1) OR ( 1 / 0 = 0)
 PRINT 1
ELSE 
 PRINT 2

您将看到IF需要一个布尔结果语句,因此可以对某些类型的布尔检查进行快捷方式(在2012年及以后工作,可能不完全向后兼容)

答案 1 :(得分:0)

要添加其他答案,SQL引擎的工作原理是它需要构建一个优化的执行计划,然后是它们。为此,它评估每个表达式,然后决定执行步骤。这属于汇编。只有在使用动态SQL时,才会动态评估查询。但即便如此,在OR陈述的情况下,这是一个不同的故事,Allan的答案很好地解释了这一故事。

答案 2 :(得分:0)

检查此文字 http://sommarskog.se/dyn-search-2008.html

尝试在查询结尾添加OPTION(RECOMPILE)。正如文章中所解释的,我猜查询优化器正在重用不适合您进行测试的查询计划。这样每次调用sp时,都会重新计算查询计划,因此它会随参数值的变化而变化。