Comment réduire la fragmentation HEAP dans SQL Server?

10

j'ai récemment découvert qu'une table de tas avait plus de 70% de fragmentation. J'ai donc décidé de faire un

ALTER TABLE dbo.myTable REBUILD

Assez drôle, après j'ai eu une fragmentation de 20%. Depuis, il n'y a plus eu d'écriture sur cette table. J'ai donc décidé de refaire la reconstruction.

Après la 2ème fois le chapeau de table fragmentation 50% donc encore plus! Je ne comprends vraiment pas comment cela peut arriver ...

smoking
la source
Que voulez-vous dire en parlant de fragmentation logique. C'est la fragmentation en termes d'utilisation des pages de données. Je sais qu'il n'y a pas d'ordre, mais les données non ordonnées ne sont pas fragmentées en soi. La fragmentation dans ce cas signifie une utilisation efficace des pages de données.
tuxmania
2
Je suppose que nous devrions nous demander quelle est la taille de la table? En lignes et en pages.
Cody Konior

Réponses:

17

Que signifie la fragmentation dans un tas

La valeur de fragmentation dans le tas que vous obtenez à partir de la colonne avg_fragmentation_in_percenten interrogeant sys.dm_db_index_physical_statsDMV indique que

Fragmentation logique pour les index ou fragmentation d'étendue pour les segments dans l'unité d'allocation IN_ROW_DATA.

En outre, le même BOL dit que

Il s'agit du pourcentage d'extensions dans le désordre dans les pages feuilles d'un segment. Une étendue en désordre est une étendue pour laquelle l'étendue qui contient la page actuelle d'un segment de mémoire n'est pas physiquement l'étendue suivante après l'étendue qui contient la page précédente.

Vous pouvez donc voir que ce n'est pas l'espace libre présent dans les pages allouées à Heap mais la séquence variable de pages qui crée la fragmentation.

Cela peut être démontré par un petit test. Créons une table de tas et insérons-y quelques enregistrements, puis vérifions la fragmentation.

create table dbo.HeapTest
(
Id INT not NULL Default (1),
Col1   char(5000) Not null Default ('Heaps Are Cool')
)

SET NOCOUNT ON

Insert into dbo.Heaptest default values
go 50

select index_type_desc,avg_fragmentation_in_percent,fragment_count,
avg_page_space_used_in_percent,record_count
from sys.dm_db_index_physical_stats(db_id(),object_id('dbo.HeapTest','U'),0,default,'detailed')

La table Heap est donc créée avec 50 enregistrements. Voici à quoi ressemble la fragmentation après la requête DMV sys.dm_db_index_physical stats

entrez la description de l'image ici

Vous pouvez voir que la avg_fragmentation_in_percentvaleur de la colonne est de 33%. Voyons maintenant comment les pages sont organisées. Cela peut être fait en utilisant une requête non documentée%%lockres%% . La requête serait

SELECT  %%lockres%%, * FROM dbo.HeapTest;

Et voici à quoi ressemble la sortie. Joindre seulement une partie pertinente de celui-ci. La requête a produit 50 lignes depuis que nous avons inséré 50 lignes dans notre table dbo.HeapTest.

entrez la description de l'image ici

Ce qu'il dit, c'est que la première page a un ID, 197la page suivante a un ID, 242les pages suivantes ont un ID continu jusqu'à ce que nous atteignons l'ID de page, 264car après cela, nous obtenons l'ID de la page 280. Donc, ce saut dans les numéros d'identification de page est ce qui cause réellement la fragmentation.

Maintenant, de peur de reconstruire le tas et d'exécuter à nouveau la commande pour voir la fragmentation et la disposition des pages. Nous obtenons une fragmentation comme

entrez la description de l'image ici

Vous pouvez voir que la fragmentation est maintenant 14%.

Voyons les numéros de page attribués

entrez la description de l'image ici

Nous n'avons qu'un seul saut, toutes les pages reçoivent un ID de page en série. Depuis un seul saut, la fragmentation a considérablement diminué.

Je reconstruis à nouveau le tas et maintenant, lorsque j'ai vérifié la fragmentation, elle avait complètement disparu. Et l'attribution des ID de page est comme

entrez la description de l'image ici

Pourquoi la fragmentation a augmenté

Maintenant, en ce qui concerne ce qui aurait pu augmenter la fragmentation, nous pouvons corroborer le fait que lorsque les pages étaient allouées au tas, elles ne seraient pas continues, comme vous l'avez vu ci-dessus, ce qui a provoqué l'augmentation de la valeur de la fragmentation a été l'augmentation des ID de PAGE alloués aux pages.

À l'arrière de la tête, vous devez également garder à l'esprit que le mot fragmentation pour HEAP n'a pas de sens, comment définiriez-vous la fragmentation pour un tas de pages non ordonnées.

Vraiment inquiet de la fragmentation

Si vous êtes vraiment confronté à un scénario où la table de segment de mémoire est fragmentée et ralentit les requêtes, il serait préférable de créer un index clusterisé sur la table plutôt que de le reconstruire. La raison en est que lorsque vous reconstruisez le tas, tous les index non cluster sous-jacents sont également reconstruits, ce qui prend beaucoup plus de temps pour le processus de reconstruction, en utilisant beaucoup de ressources et un journal des transactions gonflé. Sur un système de production, on essaierait toujours d'éviter cela. Paul a couvert cela dans sa section Mythe sur le tas .

PS: Veuillez ne pas utiliser de commande non documentée sur le système de production. C'était juste pour la démonstration.

Shanky
la source
Merci pour votre analyse détaillée. Je suis confronté à de grandes tables de tas parce que certains amateurs de coffre-fort de données pensent que c'est bien mieux que d'utiliser des index clusterisés, mais ils utilisent beaucoup de contraintes de vérification et d'index non cluster sur ces tas, donc je ne vois pas vraiment l'avantage des tas dans cette situation. Cependant, puisque je ne suis que le développeur stupide, je dois faire face à cela. Merci encore pour la perspicacité :)
tuxmania
Comment exécutez-vous select index_type_desc, avg_fragmentation_in_percent, fragment_count, avg_page_space_used_in_percent, record_count from sys.dm_db_index_physical_stats (db_id (), object_id ('dbo.HeapTest', 'U'), 0), retourne le détail une table ? il revient sur tous les index de toutes les tables pour moi même si je spécifie correctement mon nom de table dans 'object_id'
Mickael
@Mickael J'ai utilisé la fonction db_id () qui prendrait la base de données actuelle et j'ai spécifiquement donné un nom d'objet donc cela va toujours chercher dans la base de données actuelle et chercher Heaptestet donner le résultat. Je suis sûr que vous avez peut-être manqué quelque chose. Assurez-vous simplement que le niveau de compatibilité n'est pas 80 dans ce cas, la fonction db_id ne fonctionne pas
Shanky
@Shanky pourquoi ne recommandez-vous pas d'utiliser la requête non documentée %% lockres %% dans la production? Pourriez-vous l'expliquer en détail?
Ralph
@ user1624552 Tout simplement parce qu'il n'est pas documenté, cela signifie que MS ne conserve pas non plus la documentation à jour. Quels sont ses effets secondaires comment cela fonctionne-t-il n'est documenté nulle part, c'est pourquoi il est demandé ainsi. Ex il y a la commande fn_dump_dblog () qui crée un planificateur caché et ce n'est pas bon. Cette commande n'est pas non plus prise en charge. Vous pouvez l'utiliser, mais le risque repose sur vous.
Shanky