简体   繁体   中英

How do I force an OR clause over another in a WHERE clause in a query in SQL Server?

I have a big query and in the WHERE clause I have something like:

Do something

OR

Do something else

(only 1 OR)...

Right now if I run this query, SQL is taking about 13 seconds to finish.

If I remove the second part of the OR clause, the query runs VERY fast.

Shouldn't SQL execute the first part of the OR and, if true, finish the query by NOT looking at the other part of the OR?

Why is SQL looking at both sides of the OR? Why does it not start with the first one?

If I remove the second part of the OR clause, the query runs very fast.

Can someone give me some tips on how to make this happen?

EDIT - here's the query:

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 is not short circuiting in WHERE in SQL because it's not a boolean operation. It's search conditions to filter out rows so it can return all rows which fulfil either side.
So naturally you'll have to find all rows on both sides of the OR to be able to return them.

So when you have something like:

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

You will always have to find all rows which fulfil search condition 1 OR search condition 2 and return them as the result set.

Now if you did something like the following:

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

You will see that the IF requires a boolean resulted statement and therefore can shortcircut on some types of boolean checks (works in 2012 and onwards, may not be completely backwards compatibility)

To add on to the other answer, how SQL engine works is that it needs to build an optimized execution plan, which is them followed by it. For this, it evaluates every expression and then decides the steps of execution. This falls under compilation. Only if you use dynamic SQL, will the query be evaluated on the fly. But even then, in case of OR statement, it's a different story which is well explained by Allan's answer.

Check this text http://sommarskog.se/dyn-search-2008.html

Try adding OPTION(RECOMPILE) at the end of the query. As explained in the article, I guess the query optimizer is reusing a query plan that is not suited for the test your making. That way every time you call the sp the query plan will be recalculated so it will vary with the values of the parameters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM