Sql-Server

誰能幫我完成這個糟糕的查詢計劃?

  • April 26, 2019

查詢:

   SELECT Object1.Column1, Object2.Column2 AS Column3, Object2.Column4 AS Column5, 
Object3.Column6, Object3.Column7,Object1.Column8, Object1.Column9, 
Object1.Column10, Object1.Column11, Object1.Column12, Object1.Column13, 
Object1.Column14, Object1.Column15 as Column15, Object1.Column16, 
Object4.Column4 AS Column17, Object4.Column2 AS Column18, Object1.Column19,
Object1.Column20, Object1.Column21, Object1.Column22, Object1.Column23, 
Object1.Column24, Object1.Column25, Object1.Column26, Object5.Column4, 
Object1.Column27, Object1.Column28, Object1.Column29, Object3.Column30, 
Object3.Column1 as Column31, Object3.Column32 as Column33, Object1.Column34 
as Column34, ? AS Column35 , Object3.Column36 as Column37 
FROM Object6 AS Object1 
INNER JOIN Object7 AS Object3 ON Object1.Column38 = Object3.Column1 
INNER JOIN Object8 AS Object2 ON Object3.Column30 = Object2.Column1 
LEFT JOIN Object9 AS Object4 ON Object1.Column16 = Object4.Column2 
LEFT JOIN Object10 AS Object5 ON Object1.Column9 = Object5.Column2 
WHERE Object2.Column1 <> ? AND Object1.Column8 = ? 
AND ( coalesce(Column16,?)= ? ) 
AND EXISTS (
        SELECT ? 
        FROM Object11 
        WHERE Column39 = ? 
        AND Column30 = Object3.Column30) 
ORDER BY Column7 desc
OFFSET ? ROWS FETCH FIRST ? ROWS ONLY

這是查詢計劃

我知道我應該為此添加一個索引:

Database1.Schema1.Object7.Column30、Database1.Schema1.Object7.Column36、Database1.Schema1.Object7.Column6、Database1.Schema1.Object7.Column32

但是其中一列是 varchar 4000,由於該欄位的維度很大,因此無法創建它。

我注意到只有當返回的行少於獲取第一個數字時才需要 25 秒

在此處輸入圖像描述

執行計劃Object7按順序使用非覆蓋索引首先訪問Column7。然後它在該表上進行一些關鍵查找,並嵌套循環連接到其他表,最終連接結果到達TOP仍按 排序的運算符Column7

一旦它接收到足夠的行來滿足它,OFFSET ... FETCH它就可以停止向下游操作員請求更多的行。Object7.Column7SQL Server 估計在到達這一點之前它只需要從初始索引讀取 2419 行。

這個估計完全不正確。事實上,它最終會在滿足Object7之前讀取整個行並且可能會用完行OFFSET ... FETCH

semi join onObject11將行數減少了近一半,但殺手是Object6同一表上的 join on 和謂詞。這些一起將9,753,116來自半連接的行減少到2.

您可以嘗試花一些時間查看所涉及的表的統計資訊,以嘗試從這些連接中獲取基數估計值以使其更準確,或者您可以添加OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL') ),這樣計劃的成本就不會假設它可以提前停止,因為OFFSET ... FETCH- 這個肯定會給你一個不同的計劃。

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