AdventureWorks2012 データベースでこのクエリを実行しています:
_SELECT
s.SalesOrderID,
d.CarrierTrackingNumber,
d.ProductID,
d.OrderQty
FROM Sales.SalesOrderHeader s
JOIN Sales.SalesOrderDetail d
ON s.SalesOrderID = d.SalesOrderID
WHERE s.CustomerID = 11077
_
推定実行プランを見ると、次のことがわかります。
最初のインデックスシーク(右上)は、IX_SalesOrderHeader_CustomerIDインデックスを使用して、リテラル11077を検索しています。これには、2.6192行の推定値があります。
DBCC SHOW_STATISTICS ('Sales.SalesOrderHeader', 'IX_SalesOrderHeader_CustomerID') WITH HISTOGRAM
を使用すると、値11077が2つのサンプリングされたキー11019と11091の間にあることがわかります。
11019と11091の間の個別の行の平均数は2.619718であるか、またはインデックスシークで表示される推定行の値である2.61972に四捨五入されます。
理解できないのは、SalesOrderDetailテーブルに対するクラスター化インデックスシークの推定行数です。
DBCC SHOW_STATISTICS ('Sales.SalesOrderDetail', 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID')
を実行すると:
したがって、(私が参加している)SalesOrderIDの密度は3.178134E-05です。つまり、1/3.178134E-05(31465)は、SalesOrderDetailテーブル内の一意のSalesOrderID値の数と等しくなります。
SalesOrderDetailに31465の一意のSalesOrderIDがある場合、均等な分布では、SalesOrderIDあたりの行の平均数は121317(行の総数)を31465で割った値になります。平均は3.85561です。
したがって、ループされる行の推定数が2.61972で、平均が3.85561で返される場合、行の推定数は2.61972 * 3.85561 = 10.10062になると思います。
ただし、推定行数は11.4867です。
私は2番目の見積もりについての私の理解は正しくなく、数値の違いがそれを示しているようです。何が欠けていますか?
2番目の見積もりに対する私の理解は正しくないと思います。数値の違いがそれを示しているようです。何が欠けていますか?
SQL Server 2012のカーディナリティエスティメーターを使用すると、結合の選択性により、入れ子になったループ結合の内側の推定行数が決まりますが、その逆はありません。
11.4867の数値は、結合出力の計算された推定カーディナリティ(30.0919)を反復回数(2.61972)で除算することにより、derived(showplanでの表示用)です。単精度浮動小数点演算を使用した結果は、11.4867です。
それは本当にそれと同じくらい簡単です。 (論理)結合の選択性は、物理結合演算子の選択とは無関係であることに注意してください。結合がネストされたループ、ハッシュ、または結合結合物理演算子を使用して最終的に実行されるかどうかは同じです。
SQL Server 2012以前では、結合選択性(全体として)は、各テーブルのSalesOrderID
ヒストグラムを使用して推定されます(必要に応じて線形補間を使用したステップ境界整列の後、各ヒストグラムステップについて計算されます)。 SalesOrderID
テーブルに関連付けられたSalesOrderHeader
ヒストグラムも、独立したCustomerID
フィルターのスケーリング効果に合わせて調整されます。
これは、質問で提案された代替計算に根本的に「誤り」があると言っているのではありません。異なる一連の仮定を行うだけです。与えられた一連の論理演算の推定値を計算または組み合わせるには、常にさまざまな方法があります。同じデータに異なる統計手法を適用しても同じ回答が得られる、または常に1つの手法が他の手法より優れているという一般的な保証はありません。まれに気づかれることはありませんが、さまざまな統計手法の適用に起因する不整合は、単一の最終実行プラン内に現れることさえあります。
補足として、SQL Server 2014カーディナリティエスティメータは、独立したフィルタで調整されたヒストグラム情報( "coarse alignment" )を組み合わせるために別のアプローチを採用し、結果として10.1006このクエリの行:
Plan for computation:
CSelCalcExpressionComparedToExpression
(QCOL: [s].SalesOrderID x_cmpEq QCOL: [d].SalesOrderID)
Loaded histogram for column QCOL: [s].SalesOrderID from stats with id 1
Loaded histogram for column QCOL: [d].SalesOrderID from stats with id 1
Stats collection generated:
CStCollJoin(ID=4, **CARD=10.1006** x_jtInner)
CStCollFilter(ID=3, CARD=2.61972)
CStCollBaseTable(ID=1, CARD=31465 TBL: Sales.SalesOrderHeader AS TBL: s)
CStCollBaseTable(ID=2, CARD=121317 TBL: Sales.SalesOrderDetail AS TBL: d)
これはたまたま問題の計算と同じ結果になりますが、詳細な推論は異なります(つまり、想定されたネストされたループの実装に基づいていません)。