2

~14M 行のテーブルから 2158 行の ID を返すかなり複雑な SQL があります。簡単にするためにCTEを使用しています。

WHERE2 つの条件で構成されます。それらの1つをコメントアウトすると、もう1つは〜2秒で実行されます。両方を ( で区切ってOR) そのままにしておくと、クエリは約 100 秒実行されます。最初の条件だけで 1 ~ 2 秒かかり、19 行が返されます。2 番目の条件だけでは 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

4

1 に答える 1

3

OR条件の代わりに、2 つのクエリのUNION ALLを別々に使用してみてください。

何度も試しましたが、本当に助かりました。Art Of SQLでこの問題について読みました。

読んでください。パフォーマンスの問題に関する多くの有用な情報を見つけることができます。

アップデート:

関連する質問を確認する

SQLサーバークエリのUNION ALLとOR条件

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

UNION ALL は JOIN よりも高速ですか、それとも私の JOIN はうまくいきませんか?

ウェスの答えをチェック

OR の使用により、クエリ オプティマイザーが 2 番目のクエリでインデックスを使用しなくなっている可能性があります。

于 2012-08-23T12:07:22.907 に答える