Sql-Server
誰能幫我完成這個糟糕的查詢計劃?
查詢:
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.Column7
SQL Server 估計在到達這一點之前它只需要從初始索引讀取 2419 行。這個估計完全不正確。事實上,它最終會在滿足
Object7
之前讀取整個行並且可能會用完行OFFSET ... FETCH
。semi join on
Object11
將行數減少了近一半,但殺手是Object6
同一表上的 join on 和謂詞。這些一起將9,753,116
來自半連接的行減少到2
.您可以嘗試花一些時間查看所涉及的表的統計資訊,以嘗試從這些連接中獲取基數估計值以使其更準確,或者您可以添加
OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL') )
,這樣計劃的成本就不會假設它可以提前停止,因為OFFSET ... FETCH
- 這個肯定會給你一個不同的計劃。