Je gère cette requête dans la base de données AventureWorks2012 :
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
Si je regarde le plan d'exécution estimé, je vois ce qui suit:
L'index initial recherche (en haut à droite) utilise l'index ix_salesorderader_customéride et la recherche sur le littéral 11077. Il a une estimation de 2,6192 lignes.
Si j'utilise DBCC SHOW_STATISTICS ('Sales.SalesOrderHeader', 'IX_SalesOrderHeader_CustomerID') WITH HISTOGRAM
, il montre que la valeur 11077 est entre les deux touches échantillonnées 11019 et 11091.
Le nombre moyen de lignes distinctes comprises entre 11019 et 11091 est de 2,619718 ou arrondi à 2,61972, qui correspond à la valeur des lignes estimées indiquées pour la recherche d'index.
La pièce que je ne comprends pas est le nombre estimé de lignes pour l'indice en clustere recherchée contre la table salersOrderDetail.
Si je cours DBCC SHOW_STATISTICS ('Sales.SalesOrderDetail', 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID')
:
Donc, la densité du vendeur (que je rejoint) est 3.178134E-05. Cela signifie que 1/3.178134e-05 (31465) est égal au nombre de valeurs de venteOrderId uniques dans la table des vendeurs de venteOrderDetail.
S'il y a 31465 des vendeurs uniques dans la venteOrderDetail, alors avec une distribution uniforme, le nombre moyen de lignes par salopeOrderid est de 121317 (nombre total de lignes) divisé en 31465. La moyenne est 3.85561
Donc, si le nombre estimé de lignes à boucle est de 2.61972, et la moyenne à être renvoyée dans 3,85561, le nombre de lignes estimé serait de 2.61972 * 3.85561 = 10.10062.
Mais le nombre estimé de lignes est de 11,4867.
Je pense que ma compréhension de la deuxième estimation est incorrecte et les différents nombres semblent indiquer cela. Qu'est-ce que je rate?
Je pense que ma compréhension de la deuxième estimation est incorrecte et que les numéros différents semblent indiquer cela. Qu'est-ce que je manque ?
Utilisation de l'estimateur de cardinalité SQL Server 2012, la sélectivité de la jointure entraîne le nombre estimé de lignes sur le côté intérieur des boucles imbriquées Joindre, et non l'inverse.
Le numéro 11.4867 est dérivé (pour afficher dans showplan) en divisant la cardinalité estimée calculée de la sortie de jointure (30.0919) par le nombre d'itérations (2.61972). Le résultat, utilisant une arithmétique à point flottant à une précision, est 11.4867 .
C'est vraiment aussi simple que cela. Notez que la sélectivité (logique) jointure est indépendante du choix de l'opérateur de jointure physique. Il reste la même chose si la jointure est finalement effectuée à l'aide d'une boucle imbriquée, de hachage ou de fusionner un opérateur physique.
Dans SQL Server 2012 et antérieure, la sélectivité de la jointure (dans son ensemble) est estimée à l'aide des histogrammes SalesOrderID
à partir de chaque table (calculé pour chaque étape d'histogramme, après l'alignement des limites d'étape à l'aide d'une interpolation linéaire si nécessaire). Le SalesOrderID
histogramme associé au tableau SalesOrderHeader
est également ajusté pour l'effet d'échelle du filtre Independent CustomerID
.
Cela ne veut pas dire que quelque chose fondamentalement "faux" avec le calcul alternatif proposé dans la question; Cela fait simplement un ensemble d'hypothèses différents. Il y aura toujours différentes manières de calculer ou de combiner des estimations pour une séquence donnée d'opérations logiques. Il n'existe aucune garantie générale que différentes méthodes statistiques appliquées aux mêmes données produiront les mêmes réponses, ou qu'une méthode serait toujours supérieure à l'autre. Les incohérences résultant de l'application de méthodes statistiques différentes peuvent même figurer dans un seul plan d'exécution final, bien qu'ils soient rarement remarqués.
En tant que note latérale, l'estimateur de cardinalité SQL Server 2014 prend une approche différente de la combinaison des informations d'histogramme de filtrage indépendants ( "alignement grossier" ), ce qui donne une estimation finale différente de 10.1006 rangées pour cette requête:
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)
Cela se trouve être le même résultat que le calcul de la question, bien que le raisonnement détaillé soit différent (c'est-à-dire qu'il ne repose pas sur une mise en œuvre supposée des boucles imbriquées).