Comment le nombre d'étapes de l'histogramme est-il décidé dans Statistiques dans SQL Server?
Pourquoi est-il limité à 200 étapes même si ma colonne de clé a plus de 200 valeurs distinctes? Y a-t-il un facteur décisif?
Démo
Définition du schéma
CREATE TABLE histogram_step
(
id INT IDENTITY(1, 1),
name VARCHAR(50),
CONSTRAINT pk_histogram_step PRIMARY KEY (id)
)
Insérer 100 enregistrements dans ma table
INSERT INTO histogram_step
(name)
SELECT TOP 100 name
FROM sys.syscolumns
Mise à jour et vérification des statistiques
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Étapes de l'histogramme:
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 3 | 1 | 1 | 1 | 1 |
| 5 | 1 | 1 | 1 | 1 |
| 7 | 1 | 1 | 1 | 1 |
| 9 | 1 | 1 | 1 | 1 |
| 11 | 1 | 1 | 1 | 1 |
| 13 | 1 | 1 | 1 | 1 |
| 15 | 1 | 1 | 1 | 1 |
| 17 | 1 | 1 | 1 | 1 |
| 19 | 1 | 1 | 1 | 1 |
| 21 | 1 | 1 | 1 | 1 |
| 23 | 1 | 1 | 1 | 1 |
| 25 | 1 | 1 | 1 | 1 |
| 27 | 1 | 1 | 1 | 1 |
| 29 | 1 | 1 | 1 | 1 |
| 31 | 1 | 1 | 1 | 1 |
| 33 | 1 | 1 | 1 | 1 |
| 35 | 1 | 1 | 1 | 1 |
| 37 | 1 | 1 | 1 | 1 |
| 39 | 1 | 1 | 1 | 1 |
| 41 | 1 | 1 | 1 | 1 |
| 43 | 1 | 1 | 1 | 1 |
| 45 | 1 | 1 | 1 | 1 |
| 47 | 1 | 1 | 1 | 1 |
| 49 | 1 | 1 | 1 | 1 |
| 51 | 1 | 1 | 1 | 1 |
| 53 | 1 | 1 | 1 | 1 |
| 55 | 1 | 1 | 1 | 1 |
| 57 | 1 | 1 | 1 | 1 |
| 59 | 1 | 1 | 1 | 1 |
| 61 | 1 | 1 | 1 | 1 |
| 63 | 1 | 1 | 1 | 1 |
| 65 | 1 | 1 | 1 | 1 |
| 67 | 1 | 1 | 1 | 1 |
| 69 | 1 | 1 | 1 | 1 |
| 71 | 1 | 1 | 1 | 1 |
| 73 | 1 | 1 | 1 | 1 |
| 75 | 1 | 1 | 1 | 1 |
| 77 | 1 | 1 | 1 | 1 |
| 79 | 1 | 1 | 1 | 1 |
| 81 | 1 | 1 | 1 | 1 |
| 83 | 1 | 1 | 1 | 1 |
| 85 | 1 | 1 | 1 | 1 |
| 87 | 1 | 1 | 1 | 1 |
| 89 | 1 | 1 | 1 | 1 |
| 91 | 1 | 1 | 1 | 1 |
| 93 | 1 | 1 | 1 | 1 |
| 95 | 1 | 1 | 1 | 1 |
| 97 | 1 | 1 | 1 | 1 |
| 99 | 1 | 1 | 1 | 1 |
| 100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Comme nous pouvons le voir, l'histogramme comporte 53 étapes.
Insérant à nouveau quelques milliers d'enregistrements
INSERT INTO histogram_step
(name)
SELECT TOP 10000 b.name
FROM sys.syscolumns a
CROSS JOIN sys.syscolumns b
Mise à jour et vérification des statistiques
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Maintenant, les étapes de l'histogramme sont réduites à 4 étapes
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 10088 | 10086 | 1 | 10086 | 1 |
| 10099 | 10 | 1 | 10 | 1 |
| 10100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Insérant à nouveau quelques milliers d'enregistrements
INSERT INTO histogram_step
(name)
SELECT TOP 100000 b.name
FROM sys.syscolumns a
CROSS JOIN sys.syscolumns b
Mise à jour et vérification des statistiques
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Maintenant, les étapes de l'histogramme sont réduites à 3 étapes
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 110099 | 110097 | 1 | 110097 | 1 |
| 110100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Quelqu'un peut-il me dire comment ces étapes sont décidées?
la source
Réponses:
Je vais limiter ce post à la discussion des statistiques sur une seule colonne, car elles seront déjà assez longues et vous souhaitez savoir comment SQL Server classe les données en étapes d'histogramme. Pour les statistiques multi-colonnes, l'histogramme n'est créé que sur la première colonne.
Lorsque SQL Server détermine qu'une mise à jour des statistiques est nécessaire, il lance une requête masquée qui lit toutes les données d'une table ou un échantillon des données de la table. Vous pouvez afficher ces requêtes avec des événements étendus. Il existe une fonction appelée
StatMan
dans SQL Server qui est impliquée dans la création des histogrammes. Pour les objets statistiques simples, il existe au moins deux types deStatMan
requêtes différents (il existe différentes requêtes pour les mises à jour rapides des statistiques et je soupçonne que la fonctionnalité de statistiques incrémentielles sur les tables partitionnées utilise également une requête différente).Le premier saisit simplement toutes les données de la table sans aucun filtrage. Vous pouvez le voir lorsque le tableau est très petit ou que vous collectez des statistiques avec l'
FULLSCAN
option:SQL Server choisit la taille d'échantillon automatique en fonction de la taille de la table (je pense que c'est à la fois le nombre de lignes et de pages dans la table). Si un tableau est trop grand, la taille d'échantillon automatique tombe en dessous de 100%. Voici ce que j'ai obtenu pour le même tableau avec 1M de lignes:
TABLESAMPLE
est documenté mais StatMan et step_direction ne le sont pas. ici, SQL Server échantillonne environ 66,6% des données de la table pour créer l'histogramme. Cela signifie que vous pouvez obtenir un nombre différent d'étapes d'histogramme lors de la mise à jour des statistiques (sansFULLSCAN
) sur les mêmes données. Je n'ai jamais observé cela dans la pratique mais je ne vois pas pourquoi ce ne serait pas possible.Exécutons quelques tests sur des données simples pour voir comment les statistiques changent au fil du temps. Vous trouverez ci-dessous un code de test que j'ai écrit pour insérer des entiers séquentiels dans une table, rassembler des statistiques après chaque insertion et enregistrer des informations sur les statistiques dans une table de résultats. Commençons par insérer simplement 1 ligne à la fois jusqu'à 10000. Banc d'essai:
Pour ces données, le nombre d'étapes de l'histogramme augmente rapidement à 200 (il atteint d'abord le nombre maximal d'étapes avec 397 lignes), reste à 199 ou 200 jusqu'à ce que 1485 lignes soient dans le tableau, puis diminue lentement jusqu'à ce que l'histogramme n'ait que 3 ou 4 pas. Voici un graphique de toutes les données:
Voici l'histogramme ressemble à 10k lignes:
Est-ce un problème que l'histogramme ne comporte que 3 étapes? Il semble que les informations soient préservées de notre point de vue. Notez que parce que le type de données est un ENTIER, nous pouvons déterminer le nombre de lignes dans la table pour chaque entier compris entre 1 et 10 000. En règle générale, SQL Server peut le comprendre également, bien qu'il existe certains cas où cela ne fonctionne pas tout à fait . Voir cet article SE pour un exemple de cela.
Que pensez-vous qu'il se passera si nous supprimons une seule ligne du tableau et mettons à jour les statistiques? Idéalement, nous aurions une autre étape d'histogramme pour montrer que l'entier manquant n'est plus dans le tableau.
C'est un peu décevant. Si nous construisions un histogramme à la main, nous ajouterions une étape pour chaque valeur manquante. SQL Server utilise un algorithme à usage général, donc pour certains ensembles de données, nous pouvons être en mesure de proposer un histogramme plus approprié que le code qu'il utilise. Bien sûr, la différence pratique entre obtenir 0 ou 1 ligne à partir d'une table est très faible. J'obtiens les mêmes résultats lorsque je teste avec 20000 lignes, chaque entier ayant 2 lignes dans le tableau. L'histogramme ne gagne pas de pas lorsque je supprime des données.
Si je teste avec 1 million de lignes avec chaque entier ayant 100 lignes dans le tableau, j'obtiens des résultats légèrement meilleurs, mais je peux toujours construire un meilleur histogramme à la main.
Histogramme final:
Essayons plus loin avec des entiers séquentiels mais avec plus de lignes dans le tableau. Notez que pour les tableaux trop petits, la spécification manuelle d'une taille d'échantillon n'aura aucun effet, je vais donc ajouter 100 lignes dans chaque insert et collecter les statistiques à chaque fois jusqu'à 1 million de lignes. Je vois un modèle similaire à celui précédent, sauf qu'une fois arrivé à 637300 lignes dans le tableau, je n'échantillonne plus 100% des lignes du tableau avec le taux d'échantillonnage par défaut. À mesure que je gagne des lignes, le nombre de pas d'histogramme augmente. C'est peut-être parce que SQL Server se retrouve avec plus de lacunes dans les données à mesure que le nombre de lignes non échantillonnées dans la table augmente. Je ne franchis pas 200 pas, même à 1 M de rangées, mais si je continuais à ajouter des rangées, je m'attendais à y arriver et à recommencer à redescendre.
L'axe des X est le nombre de lignes du tableau. À mesure que le nombre de lignes augmente, les lignes échantillonnées varient un peu et ne dépassent pas 650k.
Faisons maintenant quelques tests simples avec les données VARCHAR.
Ici, j'insère 200 nombres (sous forme de chaînes) avec NULL.
Notez que NULL obtient toujours son propre pas d'histogramme lorsqu'il se trouve dans le tableau. SQL Server aurait pu me donner exactement 201 étapes pour conserver toutes les informations, mais il ne l'a pas fait. Techniquement, les informations sont perdues car '1111' est trié entre '1' et '2' par exemple.
Essayons maintenant d'insérer différents caractères au lieu de simples entiers:
Aucune différence réelle par rapport au dernier test.
Essayons maintenant d'insérer des caractères mais en mettant des nombres différents de chaque caractère dans le tableau. Par exemple,
CHAR(11)
a 1 ligne,CHAR(12)
2 lignes, etc.Comme auparavant, je n'obtiens toujours pas exactement 200 pas d'histogramme. Cependant, la plupart des étapes ont
RANGE_ROWS
0.Pour le test final, je vais insérer une chaîne aléatoire de 5 caractères dans chaque boucle et rassembler les statistiques à chaque fois. Voici le code de la chaîne aléatoire:
Voici le graphique des lignes du tableau par rapport aux étapes de l'histogramme:
Notez que le nombre d'étapes ne descend pas en dessous de 100 une fois qu'il commence à monter et à descendre. J'ai entendu quelque part (mais je ne peux pas le trouver pour le moment) que l'algorithme de construction d'histogramme SQL Server combine les étapes de l'histogramme lorsqu'il manque de place pour eux. Vous pouvez donc vous retrouver avec des changements drastiques dans le nombre d'étapes simplement en ajoutant un peu de données. Voici un échantillon des données que j'ai trouvé intéressantes:
Même lors de l'échantillonnage avec
FULLSCAN
, l'ajout d'une seule ligne peut augmenter le nombre d'étapes de 10, la maintenir constante, puis la diminuer de 2, puis la diminuer de 3.Que pouvons-nous résumer de tout cela? Je ne peux rien prouver de tout cela, mais ces observations semblent être vraies:
RANGE_ROWS
= 0.RANGE_HI_KEY
du tableau.DISTINCT_RANGE_ROWS
ouRANGE_ROWS
. Par exemple, 255 apparaît un tas de fois pourRANGE_ROWS
etDISTINCT_RANGE_ROWS
pour le cas de test final ici.Quand est-ce que tout cela pose problème? C'est un problème lorsqu'une requête fonctionne mal en raison d'un histogramme qui n'est pas en mesure de représenter la distribution des données de manière à ce que l'optimiseur de requête prenne de bonnes décisions. Je pense qu'il y a une tendance à penser qu'il est toujours préférable d'avoir plus d'étapes d'histogramme et qu'il y ait consternation lorsque SQL Server génère un histogramme sur des millions de lignes ou plus mais n'utilise pas exactement 200 ou 201 étapes d'histogramme. Cependant, j'ai vu beaucoup de problèmes de statistiques même lorsque l'histogramme comporte 200 ou 201 étapes. Nous n'avons aucun contrôle sur le nombre d'étapes de l'histogramme que SQL Server génère pour un objet de statistiques, donc je ne m'en inquiéterais pas. Cependant, vous pouvez suivre certaines étapes lorsque vous rencontrez des requêtes peu performantes causées par des problèmes de statistiques. Je vais donner un aperçu extrêmement bref.
La collecte complète des statistiques peut aider dans certains cas. Pour les très grands tableaux, la taille d'échantillon automatique peut être inférieure à 1% des lignes du tableau. Parfois, cela peut conduire à de mauvais plans en fonction de la perturbation des données dans la colonne. La documentation de Microsofts pour CREATE STATISTICS et UPDATE STATISTICS en dit autant:
Dans certains cas, la création de statistiques filtrées peut aider. Vous pouvez avoir une colonne avec des données asymétriques et de nombreuses valeurs distinctes différentes. S'il existe certaines valeurs dans les données qui sont généralement filtrées, vous pouvez créer un histogramme de statistiques uniquement pour ces valeurs communes. L'optimiseur de requêtes peut utiliser les statistiques définies sur une plus petite plage de données au lieu des statistiques définies sur toutes les valeurs de colonne. Vous n'êtes toujours pas garanti d'obtenir 200 étapes dans l'histogramme, mais si vous créez les statistiques filtrées sur une seule valeur, vous obtiendrez une étape d'histogramme cette valeur.
L'utilisation d'une vue partitionnée est un moyen d'obtenir efficacement plus de 200 étapes pour une table. Supposons que vous puissiez facilement diviser une grande table en une seule table par an. Vous créez une
UNION ALL
vue qui combine toutes les tables annuelles. Chaque table aura son propre histogramme. Notez que les nouvelles statistiques incrémentielles introduites dans SQL Server 2014 permettent uniquement aux mises à jour de statistiques d'être plus efficaces. L'optimiseur de requêtes n'utilisera pas les statistiques créées par partition.Il existe de nombreux autres tests qui pourraient être exécutés ici, donc je vous encourage à expérimenter. J'ai fait ces tests sur SQL Server 2014 express donc vraiment rien ne vous arrête.
la source