SQL ServerがSQL Server 2014のwhere句の「より大きい」と「等しい」をどのように推定するかを理解しようとしています。
私がそうすれば、それがステップに到達したときのカーディナリティ推定は理解していると思う
select * from charge where charge_dt >= '1999-10-13 10:47:38.550'
カーディナリティの推定値は6672で、32(EQ_ROWS)+ 6624(RANGE_ROWS)+ 16(EQ_ROWS)= 6672(下のスクリーンショットのヒストグラム)として簡単に計算できます。
しかし、私がするとき
select * from charge where charge_dt >= '1999-10-13 10:48:38.550'
(時間を10:48に増やしたため、ステップではありません)
推定値は4844.13です。
それはどのように計算されますか?
唯一の問題は、ヒストグラムのステップを処理する方法を決定することです部分的にカバーされますクエリ述語間隔。述語の範囲でカバーされる全体のヒストグラムステップは、質問で述べたように取るに足らないものです。
F
=クエリ述語がカバーするステップ範囲の割合(0〜1)。
基本的な考え方は、F
(線形補間)を使用して、述語でカバーされるステップ内の個別値の数を決定することです。この結果に個別値ごとの平均行数を掛けて(均一性があると仮定して)、ステップが等しい行を追加すると、カーディナリティの推定値が得られます。
カーディナリティ= EQ_ROWS +(AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)
レガシーCEの>
および>=
にも同じ数式が使用されます。
新しいCEは、以前のアルゴリズムを少し変更して、>
と>=
を区別します。
>
を最初にすると、式は次のようになります。
カーディナリティ= EQ_ROWS +(AVG_RANGE_ROWS *(F *(DISTINCT_RANGE_ROWS-1)))
>=
の場合:
カーディナリティ= EQ_ROWS +(AVG_RANGE_ROWS *((F *(DISTINCT_RANGE_ROWS-1))+ 1))
+ 1
は、比較に同等性が含まれる場合、一致と見なされる(包含の仮定)ことを反映しています。
質問の例では、F
は次のように計算できます。
DECLARE
@Q datetime = '1999-10-13T10:48:38.550',
@K1 datetime = '1999-10-13T10:47:38.550',
@K2 datetime = '1999-10-13T10:51:19.317';
DECLARE
@QR float = DATEDIFF(MILLISECOND, @Q, @K2), -- predicate range
@SR float = DATEDIFF(MILLISECOND, @K1, @K2) -- whole step range
SELECT
F = @QR / @SR;
結果は.728219019233034です。これを>=
の数式に他の既知の値とともに挿入します。
カーディナリティー= EQ_ROWS +(AVG_RANGE_ROWS *((F *(DISTINCT_RANGE_ROWS-1))+ 1)) = 16 +(16.1956 *((0.728219019233034 *(409-1))+ 1) ) = 16 +(16.1956 *((0.728219019233034 * 408)+ 1)) = 16 +(16.1956 *(297.113359847077872 + 1)) = 16 +(16.1956 * 298.113359847077872) = 16 + 4828.1247307393343837632 = 4844.1247307393343837632 = 4844.12473073933 (精度を浮動にする)
この結果は、質問で示された4844.13の推定値と一致します。
レガシーCEを使用した同じクエリ(たとえば、トレースフラグ9481を使用)は、次の推定値を生成する必要があります。
カーディナリティ= EQ_ROWS +(AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS) = 16 +(16.1956 * 0.728219019233034 * 409) = 16 + 4823.72307468722 = 4839.72307468722
レガシーCEを使用した>
と>=
の見積もりは同じになることに注意してください。
フィルターが「より大きい」または「より小さい」場合、行を推定する式は少し間抜けになりますが、これは到達可能な数値です。
ステップ193を使用して、関連する番号は次のとおりです。
RANGE_ROWS = 6624
EQ_ROWS = 16
AVG_RANGE_ROWS = 16.1956
前のステップのRANGE_HI_KEY = 1999-10-13 10:47:38.550
現在のステップのRANGE_HI_KEY = 1999-10-13 10:51:19.317
WHERE句の値= 1999-10-13 10:48:38.550
1)2つの範囲Hiキー間のmsを見つける
SELECT DATEDIFF (ms, '1999-10-13 10:47:38.550', '1999-10-13 10:51:19.317')
結果は220767ミリ秒です。
2)行数を調整する
ミリ秒あたりの行を見つける必要がありますが、その前に、RANGE_ROWSからAVG_RANGE_ROWSを減算する必要があります。
6624-16.1956 = 6607.8044行
3)行数を調整してミリ秒あたりの行数を計算します。
6607.8044行/ 220767 ms = .0299311行/ ms
4)WHERE句の値と現在のステップRANGE_HI_KEYの間のmsを計算します
SELECT DATEDIFF (ms, '1999-10-13 10:48:38.550', '1999-10-13 10:51:19.317')
これにより160767 msが得られます。
5)1秒あたりの行数に基づいて、このステップの行を計算します。
.0299311行/ ms * 160767 ms = 4811.9332行
6)以前にAVG_RANGE_ROWSをどのように差し引いたか覚えていますか?それらを追加する時が来ました。 1秒あたりの行数に関連する数値の計算が完了したので、EQ_ROWSも安全に追加できます。
4811.9332 + 16.1956 + 16 = 4844.1288
切り上げ、それは私たちの4844.13見積もりです。
ミリ秒あたりの行数が計算される前にAVG_RANGE_ROWSが差し引かれる理由に関する記事やブログ投稿は見つかりませんでした。 I was見積もりに含まれていることを確認できますが、文字どおり最後のミリ秒のみです。
WideWorldImportersデータベース を使用して、インクリメンタルテストを行ったところ、行の推定値の減少は線形であることがわかりましたntilステップの終わり。
これが私のサンプルクエリです:
SELECT PickingCompletedWhen
FROM Sales.Orders
WHERE PickingCompletedWhen >= '2016-05-24 11:00:01.000000'
PickingCompletedWhenの統計を更新してから、ヒストグラムを取得しました。
DBCC SHOW_STATISTICS([sales.orders], '_WA_Sys_0000000E_44CA3770')
RANGE_HI_KEYに近づくにつれて推定行がどのように減少するかを確認するために、ステップ全体でサンプルを収集しました。減少は直線的ですが、AVG_RANGE_ROWS値に等しい行数がトレンドの一部ではないかのように動作します... RANGE_HI_KEYに到達し、突然、未回収の借金のように減少します。サンプルデータ、特にグラフで確認できます。
RANGE_HI_KEYに到達するまで行が着実に減少し、最後のAVG_RANGE_ROWSチャンクであるBOOMが突然差し引かれていることに注意してください。グラフでも簡単に見つけることができます。
要約すると、AVG_RANGE_ROWSの奇妙な扱いは行推定の計算をより複雑にしますが、CEが行っていることをいつでも調整できます。
指数バックオフは、新しい(SQL Server 2014現在の)Cardinality Estimatorが複数の単一列統計を使用する場合に、より良い推定を取得するために使用する方法です。この質問は単一列の統計に関するものだったので、EBの式は含まれていません。