web-dev-qa-db-ja.com

ネストされたループの推定値が低すぎるため、tempdbが流出します

私はクエリの調整に取り組んでいますが、主な問題は、ローの見積もりが低すぎるために割り当てられたメモリが少なすぎるため、ネストされたループのステップが早い段階にあり、ダウンストリームのステップが流出することです。 tempdb。問題のある手順は、下の緑色のボックスにある手順です。

Plan

https://www.brentozar.com/pastetheplan/?id=Sk8E-6YAM

入れ子ループへの2つの入力はどちらも2.4M行の正確な行推定値を持っていますが、そのステップの出力は37行と推定されていますが、実際の行数は2.4Mです。

以下の3つのテーブルスプールの手順はすべて、見積もりと実際の見積もりがまったく同じであるため、ネストされたループから見積もりを取得していると思います。すべてのブランチは、ソートステップでtempdbにスピルします。

ネストされたループから推定された行を修正することができれば、トップブランチでのスピルが防止されるだけでなく、テーブルスプールも正しい推定を継承し、十分なメモリが付与され、さらにこぼれない。

レガシーCEがオンになっているSQL Server 2016 SP2。

これがクエリです

SELECT  Object18.Column1,
        Object18.Column3,
        Function1(Object19.Column12) AS Column13,
        Function2(Object19.Column12) AS Column14,
        Function3(DISTINCT (CASE WHEN Object19.Column15 = ? THEN Object18.Column6 END)) AS Column16,
        Function3(DISTINCT (CASE WHEN Object19.Column17 = ? THEN Object18.Column6 END)) AS Column18,
        Function3(DISTINCT Object18.Column6) AS Column19
from Object8 Object18
join Object20 Object19 on Object19.Column20 = Object18.Column7 and Object19.Column3 = Object18.Column3
where Object19.Column8 = ?
GROUP BY Object18.Column1, Object18.Column3
option (recompile)
4
Adam A

挿入後に一時テーブルにインデックスを作成することで、見積もりを修正することができました。これによりtempdbの流出は解決しましたが、パフォーマンスはそれほど向上しませんでした。最終的には、データクエリを集計から分離し、他のいくつかのクエリをシャッフルして並列化の利点を最大限に引き出し、速度を4倍に削減します。みんなありがとう、特に Joe Obbish

1
Adam A