約10億個の異なる値を持つCOUNT(DISTINCT)
の場合、約300万行しかないと推定されるハッシュ集計を使用したクエリプランを取得しています。
なぜこうなった? SQL Server 2012は適切な見積もりを生成しますが、これはSQL Server 2014のバグであり、接続について報告する必要がありますか?
クエリと不十分な見積もり
-- Actual rows: 1,011,719,166
-- SQL 2012 estimated rows: 1,079,130,000 (106% of actual)
-- SQL 2014 estimated rows: 2,980,240 (0.29% of actual)
SELECT COUNT(DISTINCT factCol5)
FROM BigFactTable
OPTION (RECOMPILE, QUERYTRACEON 9481) -- Include this line to use SQL 2012 CE
-- Stats for the factCol5 column show that there are ~1 billion distinct values
-- This is a good estimate, and it appears to be what the SQL 2012 CE uses
DBCC SHOW_STATISTICS (BigFactTable, _WA_Sys_00000005_24927208)
--All density Average Length Columns
--9.266754E-10 8 factCol5
SELECT 1 / 9.266754E-10
-- 1079126520.46229
クエリプラン
完全なスクリプト
これまでに試したこと
私は関連する列の統計を詳しく調べたところ、密度ベクトルが推定約11億の異なる値を示していることがわかりました。 SQL Server 2012はこの見積もりを使用して、適切な計画を作成します。 SQL Server 2014は、驚くべきことに、統計によって提供される非常に正確な推定を無視し、代わりにはるかに低い推定を使用しているようです。これにより、ほぼ十分なメモリを予約しない非常に遅いプランが生成され、tempdbに溢れます。
トレースフラグ4199
を試しましたが、状況は修正されませんでした。最後に、 この記事 の後半に示されているように、トレースフラグ(3604, 8606, 8607, 8608, 8612)
を組み合わせてオプティマイザ情報を掘り下げてみました。しかし、最終的な出力ツリーに表示されるまで、私は悪い見積もりを説明する情報を見ることができませんでした。
接続の問題
この質問への回答に基づいて、私はこれを Connectの問題 として提出しました
カーディナリティー推定の導出方法は、私にとって直感に反しているようです。個別のカウントの計算(拡張イベントまたはトレースフラグ2363および3604で表示可能)は次のとおりです。
キャップに注目してください。これの一般的なロジックは非常に合理的です(より明確な値はあり得ません)が、キャップはsampled複数列統計から適用されます:
DBCC SHOW_STATISTICS
(BigFactTable, [PK_BigFactTable])
WITH
STAT_HEADER,
DENSITY_VECTOR;
これは、3,439,431,721からサンプリングされた2,980,235行を示し、Col5レベルの密度ベクトルは3.35544E-07です。その逆数により、実際の数学を使用して2,980,240に丸めた2,980,235の多数の異なる値が得られます。
ここでの問題は、サンプリングされた統計を考えると、モデルが異なる値の数についてどのような仮定をする必要があるかです。私はそれが外挿することを期待しますが、それは行われず、おそらく意図的に行われます。
より直感的には、複数列の統計を使用する代わりに、Col5の密度を調べます(ただし、そうではありません)。
DBCC SHOW_STATISTICS
(BigFactTable, [_WA_Sys_00000005_24927208])
WITH
STAT_HEADER,
DENSITY_VECTOR;
ここで密度は9.266754E-10で、その逆数は1,079,126,528です。
当面の明らかな回避策の1つは、フルスキャンで複数列の統計を更新することです。もう1つは、元のカーディナリティ推定量を使用することです。
開いた接続項目 SQL 2014でサンプリングされた複数列の統計は、非先行列のより正確な単一列の統計をオーバーライドします がマークされます修正済みSQL Server 2017の場合。