簡體   English   中英

重寫WHERE NOT IN子句的最佳方法是什么?

[英]Best way to rewrite a WHERE NOT IN clause?

我有一個類似下面的查詢:

Select ser.key
From dbo.Enrlmt ser     
Where ser.wd >= @FromDate AND ser.wd <= @ThrouDate AND
      ser.EnrlmtStatCode = '4321' AND
      ser.StuExitCatgCode in ('1','2','3','4','5','6','7') AND
      ser.Key not in (select Key 
                           from Enrlmt ser2 
                          where ser2.StartDate <= @AsOfDate 
                            AND ser2.StartDate > ser.wd 
                            AND ser2.EnrlmtStatCode = '4321')

由於“NOT IN”條款,這非常慢。 我嘗試使用左外連接重寫它,使它看起來像:

   Select ser.key
     From dbo.Enrlmt ser    
LEFT JOIN dbo.Enrlmt ser2 ON ser.key = ser2.key
                         AND ser2.StartDate <= @AsOfDate 
                         AND ser2.StartDate > ser.wd 
                         AND ser2.EnrlmtStatCode = '4321'
   Where ser2.key is null
     AND ser.wd >= @FromDate 
     AND ser.wd <= @ThrouDate 
     AND ser.EnrlmtStatCode = '4321' 
     AND ser.StuExitCatgCode in ('1','2','3','4','5','6','7')

哪個更快但結果不匹配。 我這次重寫有什么問題嗎? 有一個更好的方法嗎?

也許這是一個錯字,但在第一個查詢中,您正在比較StuKey列,而在第二個查詢中,您正在加入Key

在性能方面,我希望2個查詢導致一個非常相似的(如果不是相同的)執行計划。 你應該檢查兩者的計划。

此外,請確保在運行之間清除數據緩存,因為它們實際上可以執行相同的操作,但由於緩存數據,第二個似乎更快。

我認為問題在於:

ser.StuKey not in (select StuKey

相比於:

ON ser.key = ser2.key

所以重寫應該是:

SELECT      ser.key
FROM        dbo.Enrlmt  ser
LEFT JOIN   Enrlmt      ser2
ON          ser.StuKey         = ser2.Stukey
AND         ser.EnrlmtStatCode = ser2.EnrlmtStatCode
AND         ser2.StartDate     > ser.wd
AND         ser2.StartDate     <= @AsOfDate
WHERE       ser.wd             >= @FromDate 
AND         ser.wd             <= @ThrouDate
AND         ser.EnrlmtStatCode = '4321'
AND         ser.StuExitCatgCode in ('1','2','3','4','5','6','7')
AND         ser2.key IS NULL

(注意我也刪除了ser2.EnrlmtStatCode ='4321'並將其重寫為列比較)

試試這個

  • 不存在
  • 也許不需要關聯ser2.StartDate > ser.wd因為ser.wd >= @FromDate

也:

  • 如果必須使用ser2.StartDate > ser.wd ,它們是否是相同的數據類型?
  • 所有數據類型都排成一行嗎? 例如:@ FrromDate,@ TWDate,StartDate,wd等?

從而:

Select
    ser.key
From
    dbo.Enrlmt ser     
Where
    ser.wd >= @FromDate AND ser.wd <= @ThrouDate AND
    ser.EnrlmtStatCode = '4321' AND
    ser.StuExitCatgCode in ('1','2','3','4','5','6','7') AND
    not EXISTS (select *
                           from Enrlmt ser2 
                          where ser2.StartDate <= @AsOfDate 
                            AND ser2.EnrlmtStatCode = '4321'
                            AND ser2.StartDate > @FromDate --ser.wd??
                            AND ser2.Key = ser.Key)

這將是效率和清晰度之間的良好平衡:

    Select ser.key
From
    dbo.Enrlmt ser
    Left Join (select StuKey 
            from Enrlmt 
            where Enrlmt.StartDate <= @AsOfDate AND 
            Enrlmt.EnrlmtStatCode = '4321') As ser2
    ON ser.key = ser2.key And ser2.StartDate > ser.wd
Where
        ser.wd >= @FromDate AND ser.wd <= @ThrouDate AND
        ser.EnrlmtStatCode = '4321' AND
        ser.StuExitCatgCode in ('1','2','3','4','5','6','7') AND
        ser2.key Is Null

您可以通過將子查詢設置為UDF來提高速度。 對於子查詢執行大量工作的大量記錄,請考慮將所有內容放在UDF或過程中,並使用子查詢的結果填充臨時表,使用主查詢中的該表,然后通過擦除進行清理臨時表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM