Lorsqu'une table a un index clusterisé, l'index est les données de la table (sinon vous avez une table de type segment de mémoire). Une reconstruction de l'index clusterisé (n'importe quel index en fait, mais l'espace ne serait pas compté comme "données" pour un index non clusterisé) entraînera la fusion des pages partiellement utilisées dans une forme plus complète.
Au fur et à mesure que vous insérez des données dans un index (en cluster ou autre) dans l'ordre des feuilles d'index, les pages sont créées selon les besoins et vous n'aurez qu'une seule page partielle: celle à la fin. Lorsque vous saisissez des données dans l'ordre d'index, une page doit être divisée pour que les données tiennent au bon endroit: vous vous retrouvez avec deux pages qui sont environ à moitié pleines et la nouvelle ligne va dans l'une d'entre elles. Au fil du temps, cela peut se produire beaucoup, consommant une bonne quantité d'espace supplémentaire, bien que dans une certaine mesure, les insertions futures combleront certaines lacunes. Les pages non-feuilles verront également un effet similaire, mais les pages de données réelles sont beaucoup plus importantes qu'elles ne le sont.
Les suppressions peuvent également entraîner des pages partielles. Si vous supprimez toutes les lignes d'une page, elles sont comptées comme «inutilisées» mais s'il reste une ou plusieurs lignes de données, elles sont toujours comptées comme étant utilisées. Même s'il n'y a qu'une seule ligne utilisant 10 octets dans une page, cette page compte comme 8192 octets dans le nombre d'espace utilisé. Encore une fois, les insertions futures pourraient combler une partie de l'écart.
Pour les lignes de longueur variable, les mises à jour peuvent également avoir le même effet: lorsqu'une ligne devient plus petite, elle peut laisser de l'espace dans sa page qui n'est pas facile à réutiliser plus tard, et si une ligne dans une page presque pleine s'allonge, elle pourrait forcer un fractionnement de page .
SQL Server ne passe pas de temps à essayer de normaliser les données en réorganisant la façon dont les pages sont utilisées, jusqu'à ce que cela soit explicitement indiqué à votre ordre de reconstruction d'index, car de tels exercices de récupération de place pourraient être un cauchemar pour les performances.
Je soupçonne que c'est ce que vous voyez, bien que je dirais qu'avoir suffisamment d'espace alloué pour environ 2,7 fois la quantité dont les données ont absolument besoin est un cas particulièrement mauvais. Cela peut impliquer que vous avez quelque chose de aléatoire comme l'une des clés significatives de l'index (une colonne UUID peut-être), ce qui signifie qu'il est peu probable que de nouvelles lignes soient ajoutées dans l'ordre d'index, et / ou qu'un nombre important de suppressions se soient produites récemment.
Exemple de fractionnement de page
Insertion par ordre d'index avec des lignes de longueur fixe dont quatre s'insèrent dans une page:
Start with one empty page:
[__|__|__|__]
Add the first item in index order:
[00|__|__|__]
Add the next three
[00|02|04|06]
Adding the next will result in a new page:
[00|02|04|06] [08|__|__|__]
And so on...
[00|02|04|06] [08|10|12|14] [16|18|__|__]
Maintenant, pour ajouter des lignes dans l'ordre d'index (c'est pourquoi j'ai utilisé des nombres pairs uniquement ci-dessus): Ajouter 11
signifierait soit étendre cette deuxième page (pas possible car elles sont de taille fixe), déplacer tout ce qui est supérieur à 11 vers le haut (beaucoup trop cher sur un grand index) ou fractionner la page comme ceci:
[00|02|04|06] [08|10|11|__] [12|14|__|__] [16|18|__|__]
À partir de là, l'ajout 13
et 17
ne se traduira pas par une scission car il y a actuellement de la place dans les pages pertinentes:
[00|02|04|06] [08|10|11|__] [12|13|14|__] [16|17|18|__]
mais l'ajout de 03:
[00|02|03|__] [04|06|__|__] [08|10|11|__] [12|13|14|__] [16|17|18|__]
Comme vous pouvez le voir, après ces opérations d'insertion, nous avons actuellement 5 pages de données allouées qui pourraient contenir un total de 20 lignes, mais nous n'en avons que 14 ("gaspillant" 30% de l'espace).
Une reconstruction avec des options par défaut (voir ci-dessous à propos du "facteur de remplissage") entraînerait:
[00|02|03|04] [06|08|10|11] [12|13|14|16] [17|18|__|__]
enregistrer une page dans cet exemple simple. Il est facile de voir comment les suppressions peuvent avoir un effet similaire à celui des insertions hors index.
Atténuation
Si vous vous attendez à ce que les données viennent dans un ordre assez aléatoire par rapport à l'ordre des index, vous pouvez utiliser l' FILLFACTOR
option lors de la création ou de la reconstruction d'un index pour dire à SQL Server de laisser artificiellement des lacunes à combler ultérieurement - réduisant les fractionnements de page à long terme mais prendre plus de place au départ. Bien sûr, obtenir cette valeur erronée peut aggraver les choses plutôt que d'améliorer la situation, alors manipulez-les avec soin.
Le fractionnement de page, en particulier sur l'index cluster, peut avoir une incidence sur les performances pour les insertions / mises à jour.Il FILLFACTOR
est donc parfois modifié pour cette raison au lieu du problème d'utilisation de l'espace dans les bases de données qui voient beaucoup d'activité d'écriture (mais pour la plupart des applications, où les lectures l'emportent sur les écritures de plusieurs ordres de grandeur, il est généralement préférable de laisser le facteur de remplissage à 100%, sauf dans des cas spécifiques comme lorsque vous avez des index sur des colonnes avec un contenu effectivement aléatoire).
Je suppose que d'autres bases de données de grands noms ont une option similaire, si vous avez également besoin de ce niveau de contrôle.
Mettre à jour
En ce qui concerne la ALTER INDEX
déclaration ajoutée à la question après avoir commencé à taper ce qui précède: je suppose que les options sont les mêmes que lorsque l'index a été créé (ou reconstruit pour la première fois) mais sinon, l'option de compression pourrait être très importante si elle était ajoutée temps. Dans cette déclaration également, le facteur de remplissage est défini sur 85% et non sur 100%, de sorte que chaque page feuille sera vide à ~ 15% immédiatement après la reconstruction.