Comment SQL Server sait-il que les prédicats sont corrélés?


15

Lors du diagnostic des requêtes SQL Server 2008 R2 avec une mauvaise estimation de la cardinalité (malgré une indexation simple, des statistiques à jour, etc.) et donc des plans de requête médiocres, j'ai trouvé un article de la base de connaissances peut-être lié: CORRECTIF: performances médiocres lorsque vous exécutez une requête qui contient des prédicats ET corrélés dans SQL Server 2008 ou SQL Server 2008 R2 ou SQL Server 2012

Je peux deviner ce que l'article de la base de connaissances entend par "corrélé", par exemple le prédicat n ° 2 et le prédicat n ° 1 ciblent largement les mêmes lignes.

Mais je ne sais pas comment SQL Server connaît ces corrélations. Une table a-t-elle besoin d'un index multi-colonnes contenant des colonnes des deux prédicats? SQL utilise-t-il des statistiques pour vérifier si les valeurs d'une colonne sont corrélées à une autre? Ou une autre méthode est-elle utilisée?

Je pose cette question pour deux raisons:

  1. pour déterminer laquelle de mes tables et requêtes pourrait être améliorée à l'aide de ce correctif
  2. savoir ce que je dois faire en indexation, statistiques, etc. pour affecter # 1

Réponses:


20

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';

Plan d'exécution par défaut

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 TransactionIDcolonne 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' TransactionDateobjet 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 TransactionIDet TransactionDateont 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:

Plan de post-exécution

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 TransactionIDprédicat à lui seul estimait 68 336,4 lignes et le TransactionDatepré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 ANDpré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 ANDclauses 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 TransactionDatecolonne.

DBCC SHOW_STATISTICS
    (
        'Production.TransactionHistory', 
        'stats Production.TransactionHistory TransactionDate TransactionID'
    );

Statistiques multi-colonnes

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:

Plan de statistiques multi-colonnes

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.