Considérez le simple plan de requête et d'exécution AdventureWorks illustré ci-dessous. La requête contient des prédicats liés à AND
. L'estimation de la cardinalité de l'optimiseur est de 41 211 lignes:
-- Estimate 41,211 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Utilisation de statistiques par défaut
Étant donné que les statistiques sur une seule colonne, l'optimiseur produit cette estimation en estimant séparément la cardinalité de chaque prédicat et en multipliant les sélectivités résultantes. Cette heuristique suppose que les prédicats sont complètement indépendants.
La division de la requête en deux parties facilite le calcul:
-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336;
Le tableau Historique des transactions contient 113 443 lignes au total, donc l'estimation de 68 336,4 représente une sélectivité de 68336,4 / 113443 = 0,60238533 pour ce prédicat. Cette estimation est obtenue à l'aide des informations d'histogramme de la TransactionID
colonne et des valeurs constantes spécifiées dans la requête.
-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Ce prédicat a une sélectivité estimée de 68413,0 / 113443 = 0,60306056 . Encore une fois, il est calculé à partir des valeurs constantes du prédicat et de l'histogramme de l' TransactionDate
objet statistique.
En supposant que les prédicats sont complètement indépendants, nous pouvons estimer la sélectivité des deux prédicats ensemble en les multipliant ensemble. L'estimation de cardinalité finale est obtenue en multipliant la sélectivité résultante par les 113 443 lignes du tableau de base:
0,60238533 * 0,60306056 * 113443 = 41210,987
Après l'arrondi, il s'agit de l'estimation 41 211 observée dans la requête d'origine (l'optimiseur utilise également des mathématiques à virgule flottante en interne).
Pas une bonne estimation
Les colonnes TransactionID
et TransactionDate
ont une corrélation étroite dans l'ensemble de données AdventureWorks (comme le font souvent les clés et les colonnes de date à augmentation monotone). Cette corrélation signifie que l'hypothèse d'indépendance est violée. Par conséquent, le plan de requête post-exécution affiche 68 095 lignes au lieu des 41 211 estimés:
Indicateur de trace 4137
L'activation de cet indicateur de trace modifie l'heuristique utilisée pour combiner les prédicats. Au lieu de supposer une indépendance complète, l'optimiseur considère que les sélectivités des deux prédicats sont suffisamment proches pour être corrélées:
-- Estimate 68,336.4
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13'
OPTION (QUERYTRACEON 4137);
Rappelons que le TransactionID
prédicat à lui seul estimait 68 336,4 lignes et le TransactionDate
prédicat à lui seul estimait 68 413 lignes. L'optimiseur a choisi la plus basse de ces deux estimations plutôt que de multiplier les sélectivités.
Il s'agit bien sûr d'une heuristique différente, mais qui peut aider à améliorer les estimations des requêtes avec des AND
prédicats corrélés . Chaque prédicat est considéré pour une éventuelle corrélation, et d'autres ajustements sont effectués lorsque de nombreuses AND
clauses sont impliquées, mais cet exemple sert à en montrer les bases.
Statistiques multi-colonnes
Ceux-ci peuvent aider dans les requêtes avec corrélations, mais les informations d'histogramme sont toujours basées uniquement sur la première colonne des statistiques. Les statistiques multi-colonnes candidates suivantes diffèrent donc de manière importante:
CREATE STATISTICS
[stats Production.TransactionHistory TransactionID TransactionDate]
ON Production.TransactionHistory
(TransactionID, TransactionDate);
CREATE STATISTICS
[stats Production.TransactionHistory TransactionDate TransactionID]
ON Production.TransactionHistory
(TransactionDate, TransactionID);
En prenant un seul de ceux-ci, nous pouvons voir que la seule information supplémentaire est les niveaux supplémentaires de la densité «tous». L'histogramme ne contient toujours que des informations détaillées sur la TransactionDate
colonne.
DBCC SHOW_STATISTICS
(
'Production.TransactionHistory',
'stats Production.TransactionHistory TransactionDate TransactionID'
);
Avec ces statistiques multi-colonnes en place ...
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
... le plan d'exécution affiche une estimation qui est exactement la même que lorsque seules les statistiques sur une seule colonne étaient disponibles:
Statistics objects on multiple columns also store statistical information about the correlation of values among the columns