Sql-Server

為什麼添加 TOP 1 會顯著降低性能?

  • December 29, 2021

我有一個相當簡單的查詢

SELECT TOP 1 dc.DOCUMENT_ID,
       dc.COPIES,
       dc.REQUESTOR,
       dc.D_ID,
       cj.FILE_NUMBER
FROM DOCUMENT_QUEUE dc
JOIN CORRESPONDENCE_JOURNAL cj
   ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
WHERE dc.QUEUE_DATE <= GETDATE()
 AND dc.PRINT_LOCATION = 2
ORDER BY cj.FILE_NUMBER

這給了我可怕的表現(就像從不費心等待它完成一樣)。查詢計劃如下所示:

在此處輸入圖像描述

但是,如果我刪除它,TOP 1我會得到一個看起來像這樣的計劃,它會在 1-2 秒內執行:

在此處輸入圖像描述

正確的 PK 和索引如下。

更改查詢計劃這一事實TOP 1並不讓我感到驚訝,我只是有點驚訝它使它變得更糟。

注意:我已經閱讀了這篇文章的結果並理解了 aRow Goal等的概念。我很好奇的是如何更改查詢以使其使用更好的計劃。目前我正在將數據轉儲到臨時表中,然後將第一行從中拉出。我想知道是否有更好的方法。

編輯對於事後閱讀本文的人來說,這裡有一些額外的資訊。

  • Document_Queue - PK/CI 是 D_ID,它有大約 5k 行。
  • Correspondence_Journal - PK/CI 是 FILE_NUMBER、CORRESPONDENCE_ID,它有大約 140 萬行。

當我開始時沒有其他索引。我最終在 Correspondence_Journal (Document_Id, File_Number) 上找到了一個

嘗試強制雜湊連接*

SELECT TOP 1 
      dc.DOCUMENT_ID,
      dc.COPIES,
      dc.REQUESTOR,
      dc.D_ID,
      cj.FILE_NUMBER
FROM DOCUMENT_QUEUE dc
INNER HASH JOIN CORRESPONDENCE_JOURNAL cj
       ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
      AND dc.QUEUE_DATE <= GETDATE()
      AND dc.PRINT_LOCATION = 2
ORDER BY cj.FILE_NUMBER

優化器可能認為循環使用 top 1 會更好,這是有道理的,但實際上它在這裡不起作用。這裡只是一個猜測,但可能該閥芯的估計成本已關閉 - 它使用 TEMPDB - 您可能有一個性能不佳的 TEMPDB。


  • 小心連接提示,因為它們強制計劃表訪問順序與查詢中表的寫入順序相匹配(就像OPTION (FORCE ORDER)已指定一樣)。從文件連結:

BOL 提取物

這在範例中可能不會產生任何不良影響,但總的來說,它很有可能。FORCE ORDER(隱含的或顯式的)是一個非常強大的提示,超出了執行命令的範圍;它阻止應用廣泛的優化器技術,包括部分聚合和重新排序。

在合適的情況下,OPTION (HASH JOIN) 查詢提示的侵入性可能較小,因為這並不意味著FORCE ORDER. 但是,它確實適用於查詢中的所有聯接。其他解決方案可用。

引用自:https://dba.stackexchange.com/questions/127639