Sql中的WHERE,结合两个快速条件会成倍增加成本

Posted

技术标签:

【中文标题】Sql中的WHERE,结合两个快速条件会成倍增加成本【英文标题】:WHERE in Sql, combining two fast conditions multiplies costs many times 【发布时间】:2012-08-18 22:23:25 【问题描述】:

我有一个相当复杂的 sql,它从大约 14M 行的表中返回 2158 行的 id。我正在使用 CTE 进行简化。

WHERE 包含两个条件。如果我注释掉其中一个,另一个会在大约 2 秒内运行。如果我将它们都保留(由OR 分隔),则查询运行约 100 秒。单独第一个条件需要1-2秒,返回19行,单独第二个条件需要0秒,返回2139行。

可能是什么原因?

这是完整的 SQL:

WITH fpcRepairs AS
(
    SELECT FPC_Row = ROW_NUMBER()OVER(PARTITION BY t.SSN_Number ORDER BY t.Received_Date, t.Claim_Creation_Date, t.Repair_Completion_Date, t.Claim_Submitted_Date)
    ,   idData, Repair_Completion_Date, Received_Date, Work_Order, SSN_number, fiMaxActionCode, idModel,ModelName
    ,   SP=(SELECT TOP 1 Reused_Indicator FROM tabDataDetail td INNER JOIN tabSparePart sp ON td.fiSparePart=sp.idSparePart
            WHERE td.fiData=t.idData
            AND (td.Material_Quantity <> 0) 
            AND (sp.SparePartName = '1254-3751'))
    FROM   tabData AS t INNER JOIN
       modModel AS m ON t.fiModel = m.idModel 
    WHERE (m.ModelName = 'LT26i') 
    AND EXISTS(
        SELECT  NULL 
        FROM    tabDataDetail AS td 
        INNER JOIN tabSparePart AS sp ON td.fiSparePart = sp.idSparePart
        WHERE  (td.fiData = t.idData) 
        AND (td.Material_Quantity <> 0) 
        AND (sp.SparePartName = '1254-3751')
    ) 
), needToChange AS
(
    SELECT idData FROM tabData AS t INNER JOIN
       modModel AS m ON t.fiModel = m.idModel
    WHERE (m.ModelName = 'LT26i') 
    AND EXISTS(
        SELECT  NULL 
        FROM    tabDataDetail AS td 
        INNER JOIN tabSparePart AS sp ON td.fiSparePart = sp.idSparePart
        WHERE  (td.fiData = t.idData) 
        AND (td.Material_Quantity <> 0) 
        AND (sp.SparePartName IN ('1257-2741','1257-2742','1248-2338','1254-7035','1248-2345','1254-7042'))
    ) 
)
SELECT t.idData
FROM tabData AS t INNER JOIN modModel AS m ON t.fiModel = m.idModel
INNER JOIN needToChange ON t.idData = needToChange.idData  -- needs to change FpcAssy
LEFT OUTER JOIN fpcRepairs rep ON t.idData = rep.idData
WHERE   
rep.idData IS NOT NULL          -- FpcAssy replaced, check if reused was claimed correctly
AND rep.FPC_Row > 1             -- other FpcAssy repair before
AND (
    SELECT SP FROM fpcRepairs lastRep
    WHERE lastRep.SSN_Number = rep.SSN_Number
    AND lastRep.FPC_Row = rep.FPC_Row - 1
) = rep.SP                      -- same SP, must be rejected(reused+reused or new+new)
OR      
rep.idData IS NOT NULL          -- FpcAssy replaced, check if reused was claimed correctly
AND rep.FPC_Row = 1             -- no other FpcAssy repair before
AND rep.SP = 0                  -- not reused, must be rejected
order by t.idData 

这是执行计划:

下载:http://www.filedropper.com/exeplanfpc

【问题讨论】:

您是否尝试分别使用 2 个查询的 UNION 而不是 OR 条件? @hgulyan:如果您将其发布为答案,我至少会支持它。使用UNION ALL 只需 3 秒。为什么? 好的,谢谢。我只是不确定是不是你的情况。也试试 UNION,而不是 UNION ALL :) @hgulyan:我为什么要使用UNIONUNION ALL 更快,两个条件互斥(FPC_Row = 1 和 FPC_Row > 1)。 @TimSchmelter - 回复:为什么?见***.com/q/5901791/73226 【参考方案1】:

尝试分别使用 UNION ALL 的 2 个查询,而不是 OR 条件。

我已经尝试了很多次,它确实很有帮助。我在Art Of SQL 中读到过这个问题。

阅读它,您可以找到许多有关性能问题的有用信息。

更新:

检查相关问题

UNION ALL vs OR condition in sql server query

http://www.sql-server-performance.com/2011/union-or-sql-server-queries/

Can UNION ALL be faster than JOINs or do my JOINs just suck?

查看韦斯的答案

OR 的使用可能导致查询优化器在第二个查询中不再使用索引。

【讨论】:

以上是关于Sql中的WHERE,结合两个快速条件会成倍增加成本的主要内容,如果未能解决你的问题,请参考以下文章

如何比较 SQL where 条件中的两个逻辑表达式? [关闭]

SQL Server增删改查语句

SQL Server数据库————增删改查

angularJS结合C#怎么对sqlserver数据库中的数据进行增删改查

SQLServer之T-SQL增删改查

SQL server 数据库