Statistiques. Les histogrammes multicolonnes sont-ils possibles?

13

Je pense à une situation où j'ai deux colonnes à haute densité mais ces colonnes ne sont pas indépendantes.

Définition

Voici la définition de la table que j'ai créée à des fins de test.

CREATE TABLE [dbo].[StatsTest](
    [col1] [int] NOT NULL,  --can take values 1 and 2 only
    [col2] [int] NOT NULL,  --can take integer values from 1 to 4 only
    [col3] [int] NOT NULL,  --integer. it has not relevance just to ensure that each row is different
    [col4]  AS ((10)*[col1]+[col2])  --a computed column ensuring that if two rows have different values in col1 or col2 have different values in col4 
) ON [PRIMARY]

Les données

Les données de l'expérience sont les suivantes

col1    col2    col3    col4
1       1       1       11
1       2       2       12
1       2       3       12
1       3       4       13
1       3       5       13
1       3       6       13
1       4       7       14
1       4       8       14
1       4       9       14
1       4       10      14
2       1       11      21
2       1       12      21
2       1       13      21
2       1       14      21
2       2       15      22
2       2       16      22
2       2       17      22
2       3       18      23
2       3       19      23
2       4       20      24

Étape 1: filtrage par col1

SELECT * FROM StatsTest WHERE col1=1

Comme prévu, l'Optimiseur de requête devine le nombre exact de lignes. Nombre réel de lignes = 10 et nombre estimé de lignes = 10

Étape 2: filtrage par col2

SELECT * FROM StatsTest WHERE col2=1

Encore une fois, nous avons une estimation parfaite.

Nombre réel de lignes = 5 et nombre estimé de lignes = 5

Étape 3: filtrage par col1 et col2

SELECT * FROM StatsTest WHERE col1=1 AND col2=1

Ici, l'estimation est loin d'être proche du nombre réel de lignes. Nombre réel de lignes = 1 et nombre estimé de lignes = 3 53553

Le problème est que l'implicité de l'analyseur de requêtes suppose que col1 et col2 sont indépendantes mais ne le sont pas.

Étape 4: filtrage par col4

SELECT * FROM StatsTest WHERE col4 = 11

Je peux filtrer par col4 = 11 pour obtenir les mêmes résultats que la requête de l'étape 3, car col4 est une colonne calculée et selon la façon dont elle a été définie col1 = 1 et col2 = 1 est équivalent à col4 = 11 Ici, cependant, , comme prévu, l'estimation est parfaite.

Nombre réel de lignes = 1 et nombre estimé de lignes = 1

Conclusion / Question

¿Cette solution artificielle et inélégante est-elle la seule option disponible pour obtenir des estimations précises lors du filtrage par deux colonnes ou plus non indépendantes? ¿La colonne calculée et le filtre par la colonne calculée sont-ils strictement nécessaires pour obtenir une précision réelle?

Exemple dans sqlfiddle

JGA
la source
Pourquoi ne pas construire des index sur col1 / 2?
LowlyDBA
En fait, je l'ai fait mais je ne l'ai pas inclus ici parce que cela n'a pas fonctionné. Pour l'histogramme, seule la première colonne est prise en compte et la densité ne prend en compte que le nombre différent de valeurs et non leur distribution
JGA

Réponses:

15

Les histogrammes multicolonnes sont-ils possibles?

Pas de vrais histogrammes multidimensionnels, non.

Cette solution artificielle et inélégante est-elle la seule option disponible pour obtenir des estimations précises lors du filtrage par deux colonnes ou plus non indépendantes?

SQL Server prend en charge les statistiques "multi-colonnes" , mais il capture uniquement les informations de densité moyenne (corrélation) en plus d'un histogramme sur la première colonne nommée. Ils ne sont utiles que pour les comparaisons d'égalité.

Les informations de densité moyenne ne capturent aucun détail, vous obtiendrez donc la même sélectivité pour n'importe quelle paire de valeurs sur un objet statistique à deux colonnes. Dans certains cas, les statistiques multi-colonnes peuvent être suffisantes et meilleures que rien. Les statistiques multi-colonnes sont automatiquement basées sur des index multi-colonnes.

Selon la version de SQL Server, vous pouvez également être en mesure d'utiliser des index filtrés et des statistiques filtrées :

-- Filtered statistics example
CREATE STATISTICS stats_StatsTest_col2_col1_eq_1
ON dbo.StatsTest (col2)
WHERE col1 = 1;

CREATE STATISTICS stats_StatsTest_col2_col1_eq_2
ON dbo.StatsTest (col2)
WHERE col1 = 2;

Ou vous pouvez créer une vue indexée (qui peut prendre en charge ses propres index et statistiques). Les vues indexées sont le mécanisme derrière le DATE_CORRELATION_OPTIMIZATIONparamètre de base de données , une fonction peu utilisée pour les corrélations inter-tables, mais qui s'applique à l'esprit de la question.

La colonne calculée et le filtre par la colonne calculée sont-ils strictement nécessaires pour obtenir une précision réelle?

Ce n'est pas la seule méthode. En plus des éléments déjà mentionnés, vous pouvez également spécifier la définition textuelle exacte de la colonne calculée et l'optimiseur la fera généralement correspondre aux statistiques de la colonne calculée.

Il existe également des indicateurs de trace qui modifient les hypothèses émises sur les corrélations multi-colonnes. En outre, l'hypothèse de corrélation par défaut dans SQL Server 2014 (avec le nouvel estimateur de cardinalité activé) est passée de l'indépendance à l'interruption exponentielle (plus de détails ici et ici ). En fin de compte, ce n'est qu'une hypothèse différente. Ce sera mieux dans de nombreux cas, et pire dans d'autres.

Une précision exacte dans l'estimation de la cardinalité n'est pas toujours nécessaire pour obtenir un bon plan d'exécution. Il y a toujours un compromis entre la génération d'un plan qui peut être réutilisé pour différentes valeurs de paramètre et un plan qui est optimal pour une exécution spécifique, mais pas réutilisé.

Paul White 9
la source