Reconstruire un très grand index de clé primaire

13

J'ai une base de données SQL hébergée sur Azure. Le problème est que la taille devient hors de contrôle, je peux voir jusqu'à 99% de fragmentation dans les index clusterisés de la clé primaire.

Je suis capable de reconstruire tous les autres index avec online=onoption et cela n'affectera pas les performances. La taille de l'un des index PK Clustered est supérieure à 200 Go, et pour celui-ci, un REBUILD...WITH (ONLINE=ON)verrouillage se produit.

Nous avons des utilisateurs de tous les fuseaux horaires qui accèdent au site, donc vraiment, je ne peux pas trouver un moment où je peux reconstruire l'index hors ligne.

Quelle est la meilleure stratégie pour reconstruire de gros index sans avoir de temps d'arrêt sur le site?

Je pense que la réorganisation n'aidera pas car la fragmentation est de 99%. Le problème est que la table est verrouillée même en ligne. Le principal problème est que l'indice est supérieur à 200 Go. La clé primaire est un entier.

Irritable
la source
4
@Techy, même avec une fragmentation élevée, REORGANIZEréduira la fragmentation des pages foliaires et l'espace compact comme REBUILD, juste moins efficacement. Êtes-vous sûr que la grande taille est due à la fragmentation? Quel est le facteur de remplissage?
Dan Guzman
Savez-vous ce qui cause la fragmentation? Combien de temps après votre reconstruction serez-vous de retour à la case 1? Pouvez-vous publier plus d'informations sur votre table?
pacreely
2
@Techy J'ai modifié la question pour ajouter des informations supplémentaires en fonction de vos commentaires. Il serait utile que vous incluiez également la définition de la table dans la question, ainsi que des détails supplémentaires concernant «la table est verrouillée même lors de la [reconstruction] en ligne». Quels types d'attente voyez-vous?
AMtwo

Réponses:

9

Même s'il est un peu tard, je vais répondre à une question dans l'espoir que cela aide ou au moins repousse quelques idées / commentaires supplémentaires sur cette question car je pense que c'est une bonne question.

Tout d'abord, et je ne sais pas si vous faites cela ou non, mais ne supposez pas que des niveaux de fragmentation élevés sur l'index entraîneront toujours de mauvaises performances. Les statistiques obsolètes (par exemple sys.dm_db_stats_properties ) et les quantités élevées d'espace blanc par page (c'est-à- dire la colonne avg_page_space_used_in_percent dans sys.dm_db_index_physical_stats dmv ) ont plus de pertinence concernant les problèmes de performances que la fragmentation seule. Oui, les index hautement fragmentés généreront plus de lectures anticipées et vous voyez généralement des statistiques obsolètes et des niveaux plus élevés d'espace blanc par page couplés à la fragmentation, mais la fragmentation n'est pas directement liée aux optimisations du plan de requête ni à la quantité de mémoire chargeant l'index à partir du disque va effectivement consommer. Les plans de requête sont affectés par les statistiques et votre empreinte mémoire gonfle avec plus d'espace blanc . Par exemple, un indice fragmenté à 99% mais dont la moyenne est inférieure à 5%. les espaces blancs et les statistiques à jour ne vous causent probablement pas de problèmes de performances drastiques par rapport à un mauvais plan d'exécution en raison de statistiques obsolètes ou à la pagination constante d'un index trop grand pour tenir pleinement en mémoire car il y a une quantité importante d'espace blanc présent par page.

Si la fragmentation est vraiment un problème , vous pouvez la réduire, EN LIGNE, en émettant une ALTER INDEX ... REORGANIZEdéclaration identifiée par Dan Guzman dans les commentaires. Cela ne créera pas un index aussi rationalisé qu'une REBUILDopération, mais cela réduira votre fragmentation. La clé ici est d'identifier les fenêtres de moindre utilisation sur votre base de données et de l'exécuter ensuite. Cela peut durer 15 minutes ou plusieurs heures, évidemment plus c'est long, mieux c'est, mais la clé ici est que cette opération ne revient pas en arrière et conserve toute progression même si vous la tuez en cours d'exécution.

Si, dans un monde parfait où votre fragmentation a été éliminée, serait-il plus judicieux d'utiliser le partitionnement sur cette table? Azure SQL Database permet le partitionnement de table et Microsoft a un excellent article décrivant certaines stratégies de partitionnement pour Azure SQL Database . Si vos données ne sont pas volatiles, le partitionnement peut aider à réduire les besoins de maintenance et, s'il est associé à la compression de table , vous pouvez même être en mesure de réduire votre empreinte de stockage globale. La réponse précédente d' Alberto Murillo fait allusion à l'utilisation du partitionnement horizontal basé sur une région de données, et cette approche peut aider à créer des fenêtres de maintenance pour vous car vos données seraient plus spécifiques à la région qu'au lieu de globales.

La transition vers une table partitionnée ne sera pas facile avec votre absence actuelle de fenêtres de maintenance, mais vous pourrez peut-être utiliser une approche décrite par Maria Zakourdaev qui utilise des vues partitionnées sur le dessus de votre table actuelle et une nouvelle table partitionnée pour commencer le partitionnement données futures. Au fil du temps (et, espérons-le, vos anciennes données sont purgées), vous pouvez éventuellement passer complètement à la table partitionnée. Encore une fois, je ne connais pas vos données ou votre application, mais cette approche est peut-être quelque chose que vous pouvez utiliser.

John Eisbrener
la source
4

Tout d'abord, il est important de déterminer si la fragmentation est importante.

Si votre requête ne fait que des recherches sur une seule ligne, vous ne remarquerez peut-être pas du tout la fragmentation. Sur les SAN modernes, la mise en cache au niveau du SAN peut rendre les E / S phyiscales suffisamment rapides pour que la fragmentation n'ait pas d'importance. Sur SSD, le modèle d'E / S aléatoire provoqué par l'analyse d'un index fragmenté peut en fait entraîner de meilleures performances que les données non fragmentées.

Souvent, les utilisateurs remarquent que la reconstruction d'un index a résolu un problème de performances. La reconstruction d'un index génère également de nouvelles statistiques. Il se peut que le vrai correctif soit de nouvelles statistiques, et non la reconstruction de l'index. UPDATE STATISTICS...WITH FULLSCANpeut être un moyen moins coûteux, plus rapide et moins intrusif de résoudre le même problème de performances.

Si vous ne rencontrez pas de problèmes causés par la fragmentation, vous pourriez dépenser beaucoup de temps et d'efforts sans gain réel.

Deuxièmement, il existe deux types de fragmentation:

  1. Fragmentation physique. C'est ce à quoi la plupart des gens pensent lorsqu'ils pensent à la fragmentation. Les pages sont hors service et doivent être réorganisées. Lors de l' analyse d' un index, ce type de fragmentation peut parfois poser problème. J'ai généralement remarqué que cela avait le plus grand impact sur les performances des lectures physiques . Si vous regardez les résultats de sys.dm_db_index_physical_stats, ce nombre est la avg_fragmentation_in_percentcolonne.

  2. Fragmentation de faible densité. Cette fragmentation est causée par des pages qui ne sont que partiellement remplies de données. Vous avez une faible densité de données car vos données sont réparties sur plus de pages que nécessaire. Par conséquent, la lecture des données nécessite plus d'E / S car les données sont réparties sur plus de pages que nécessaire. Cela peut affecter les lectures logiques et physiques. Si vous regardez les résultats de sys.dm_db_index_physical_stats, ce nombre est la avg_page_space_used_in_percentcolonne. Cette colonne n'est remplie que lors de l'utilisation du mode SAMPLEDou DETAILED.

Alors, que faites-vous à ce sujet:

Fragmentation physique : si vous recherchez simplement des chiffres élevés avg_fragmentation_in_percent, pensez vraiment à ne pas perdre votre temps. Assurez-vous que votre requête ne fonctionne pas correctement et utilisez un environnement de test pour confirmer que vous résolvez un problème en éliminant la fragmentation.

Vous pouvez résoudre la fragmentation physique en faisant ALTER INDEX...REORGANIZE. L' REORGANIZEopération est en ligne, déplaçant les pages une à la fois pour les réorganiser dans l'ordre physique. Si vous tuez une REORGANIZEinstruction en cours de route, tout travail déjà effectué est conservé - seule la page en cours de déplacement sera restaurée. Faire une REORGANIZEsur une grande table très fragmentée peut nécessiter plus d'espace total de journal des transactions et, en mode de récupération complète, peut générer une quantité importante de sauvegardes du journal des transactions. Cela peut également prendre plus de temps à REORGANIZEun index très fragmenté qu'à REBUILDlui.

Vous verrez souvent des conseils pour effectuer un REBUILDsur des index hautement fragmentés, plutôt qu'un REORGANIZE- C'est parce que la reconstruction à partir de zéro peut être plus efficace. Cependant, la réorganisation peut être une opération «plus en ligne» et est parfois préférée, même pour des index très fragmentés.

La fragmentation de faible densité ne peut pas être corrigée par REORGANIZE. Il ne peut être corrigé qu'en faisant un ALTER INDEX...REBUILD. En faisant l'index avec ONLINE=ON, vous devriez pouvoir minimiser le blocage. Cependant, le REBUILDdoit encore prendre un verrou pendant un moment pour échanger l'ancien index pour le nouvel index. Sur un système très occupé, atteindre ce verrou exclusif peut parfois être un problème. Vous devriez être en mesure de confirmer si vous rencontrez ce problème en utilisant quelque chose comme sp_whoisactive pour examiner le blocage lors de votre reconstruction et en examinant les détails des verrous et des attentes. L'utilisation de l' WAIT_AT_LOW_PRIORITYoption peut être utile si vous savez qu'il y a une période de faible utilisation à venir et que votre reconstruction peut se «faufiler» pour ce swap lorsque l'activité baisse suffisamment pour atteindre ce verrou. Notez qu'un long termeREBUILDl'opération va également être une transaction ouverte de longue durée. Les transactions ouvertes de longue durée peuvent avoir leurs propres problèmes, liés à l'utilisation / la réutilisation du journal des transactions. Si vous utilisez la mise en miroir ou des groupes de disponibilité, vous devez également tenir compte du rétablissement du journal des transactions sur le réplica secondaire.

AMtwo
la source
La fragmentation de faible densité (aka "fragmentation interne") est souvent fixée par a REORGANIZE. Extrait du BOL : "La réorganisation compacte également les pages d'index." Eh bien, aussi longtemps que le FILLFACTOR actuel de l'indice permettra la densité que vous recherchez.
Granger
2

Remarquer

Après ce commentaire:

Vous perdrez des lignes insérées lors de la copie. Si vous voulez éviter cela en verrouillant la table, vous vous retrouvez avec le même problème que l'OP indiqué dans sa question. De plus, 200 Go ne viendront pas gratuitement :-) - Marco 5 septembre 17 à 11:18

... Je vois comment cette approche ne fonctionnera pas.

Je vais laisser cette réponse comme un exemple de ce qu'il ne faut pas faire.


Si vous disposez de plus de 200 Go d'espace libre sur votre base de données Azure, vous pouvez vous faufiler avec la «reconstruction», en copiant vos données dans une table totalement nouvelle et en les y commandant.

Essayer:

  • votre script LiveTabledans un videNewTable
  • copier le LiveTabledans leNewTable
  • renommer LiveTableenOldTable
  • renommer NewTableenLiveTable

De toute évidence, utilisez le nom de votre table au lieu de LiveTable.

Oreo
la source
Oreo, j'utiliserais la même approche que toi. Même lorsqu'il y a des lignes insérées pendant la copie, vous pouvez toujours les ajouter après que le NewTable a été renommé en LiveTable. Le principal problème que vous évitez ici est le temps d'arrêt prolongé. Vous pouvez même le bcp (copie d'E / S dans). Ce n'est pas une si mauvaise idée, donc je ne comprends pas non plus le downvote :-)
Koen D
1

Idéalement, si un index est bien conçu, nous ne devrions pas avoir besoin de jouer avec le mécanisme de verrouillage.

Il me semble que vous devrez accepter le verrouillage pour défragmenter l'index clusterisé. S'il y a de fortes chances que cela se reproduise, envisagez de repenser l'index clusterisé (il devrait être étroit, unique, statique et en constante augmentation).

Je ne sais pas quelle version de SQL Server vous utilisez, mais vous pouvez essayer ce qui suit en 2012:

  • SET DEADLOCK_PRIORITY LOW - Cela indique au moteur que la reconstruction de l'index doit être la victime du blocage lorsque / si elle se produit.

  • MaxDOP = 1 - La valeur MaxDOP limite le nombre total de CPU logiques utilisées en parallèle pour créer l'index (à partir de 2005 - édition Enterprise uniquement).

Vous pouvez également modifier la configuration des verrous de page / ligne, mais je ne le ferais pas sans tester. Vous pourriez simplement aggraver le verrouillage, surtout s'il s'agit d'un index mal conçu.

À partir de 2014, il existe l'option suivante qui indique essentiellement au moteur d'autoriser d'autres sessions et à l'opération d'indexation en ligne d'attendre:

(WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF))
GPep
la source
0

J'ai utilisé la même approche que Oreo décrite ci-dessus avec beaucoup de succès! La seule chose qui manque, c'est que vous devez exécuter un script de mise à jour après avoir copié les données et effectué le dernier changement de nom.

La mise à jour ressemblera à ceci:

Insert from OldTable into LiveTable
  Where not exists (select From OldTable Where LiveTable.Key = OldTable.Key)

Si Clé est une colonne Identité, vous devez utiliser une approche légèrement différente.

CFF
la source
Comme indiqué dans la réponse d'Oreo, sa méthode ne fonctionnera pas s'il y a encore des données ajoutées à la table d'origine, sauf si vous verrouillez la table d'origine qui va à l'
encontre de
-2

Essayez d'utiliser le sharding pour distribuer géographiquement les données de votre base de données. Vous pourrez alors identifier différentes fenêtres de maintenance pour chaque emplacement géographique, et le temps de maintenance sera plus court. Cela améliorera également les performances. Vous pouvez en savoir plus sur cet article. N'attendez pas que la base de données s'agrandisse.

Avec de grandes bases de données et des utilisateurs connectés 24h / 24 et 7j / 7, vous devez utiliser l'index réorganiser et mettre à jour uniquement les statistiques qui doivent être mises à jour (sp_updatestats) pour minimiser le temps nécessaire à la maintenance et l'impact sur les utilisateurs.

J'espère que cela t'aides.

Alberto Morillo
la source