ALTER INDEX ALL REBUILD utilise-t-il plus d'espace de journal des transactions avec un modèle de récupération simple que de reconstruire chaque index individuellement?

18

Une opération «ALTER INDEX ALL REBUILD» sur SQL Server 2012 a échoué car le journal des transactions manquait d'espace. Les index n'ont jamais été réorganisés ou reconstruits, la fragmentation est donc supérieure à 80% sur presque tous.

La base de données utilise un modèle de récupération simple. J'ai supposé qu'après chaque opération d'indexation effectuée par le formulaire "ALL" de la commande, les données du journal des transactions seraient vidées avant la prochaine reconstruction d'index. Est-ce ainsi que cela fonctionne réellement, ou les reconstructions d'index sont-elles enregistrées comme si elles faisaient partie d'une seule transaction?

En d'autres termes, pourrais-je réduire la croissance du journal des transactions en écrivant un script pour effectuer chaque reconstruction individuellement? Y a-t-il d'autres facteurs à considérer?

Échec de Google
la source
2
Sauf données explicites contraires, je suppose qu'une commande SQL spécifique serait considérée comme une transaction atomique unique par le moteur de base de données. Dans ce cas, vous pouvez tester assez facilement la théorie. Prenez votre plus grand index et essayez de simplement le reconstruire. Si cela réussit, il est raisonnable de supposer que le journal accumule des informations provenant de plusieurs reconstructions. S'il échoue, vous devez ajouter de l'espace pour le journal (car vous avez un problème de toute façon), ou vous devez essayer de réorganiser cet index, au lieu de reconstruire (si vous ne pouvez pas augmenter l'espace pour le t- Journal).
RDFozz
Oui, cette pensée m'est venue juste au moment où j'ai fini de taper ceci (effet canard en caoutchouc), mais j'ai pensé qu'il serait préférable d'obtenir une confirmation et de laisser cela à d'autres qui pourraient penser de la même façon. Je ne veux pas expérimenter avec cet environnement, donc je finirai probablement par ajouter de l'espace aux journaux de toute façon.
Google Fail

Réponses:

16

J'ai supposé qu'après chaque opération d'indexation effectuée par le formulaire "ALL" de la commande, les données du journal des transactions seraient vidées avant la prochaine reconstruction d'index. Est-ce ainsi que cela fonctionne réellement, ou les reconstructions d'index sont-elles enregistrées comme si elles faisaient partie d'une seule transaction?

1) Purge du journal: le modèle de récupération SIMPLE n'efface pas le journal après chaque transaction, mais aux points de contrôle. ( lien pour plus d'informations)

2a) RECONSTRUIRE TOUT: oui, RECONSTRUIRE TOUT fonctionne comme une transaction unique. Les reconstructions d'index à l'intérieur ont leurs propres transactions, mais l'opération globale n'est pas entièrement validée jusqu'à la fin. Alors oui, vous pouvez limiter la croissance des fichiers journaux en reconstruisant des index individuels (et éventuellement en émettant des commandes CHECKPOINT).

2b) La preuve! Ici, ayez un script de démonstration. (Construit en 2016 dev) Tout d'abord, configurez une base de données de test, avec table et index:

USE master
GO

CREATE DATABASE Test_RebuildLog
GO

ALTER DATABASE Test_RebuildLog
SET RECOVERY SIMPLE
GO

USE Test_RebuildLog
GO

CREATE TABLE IndexTest
(ID int identity(1,1),
a char(1),
b char(1))

CREATE CLUSTERED INDEX CIX_IndexTest_ID ON IndexTest(ID)
CREATE INDEX IX_IndexTest_a ON IndexTest(a)
CREATE INDEX IX_IndexTest_b ON IndexTest(b)

INSERT IndexTest
(a,b)
VALUES ('a','b'),('z','y'),('s','r')

Vous pouvez maintenant comparer l'activité du journal entre RECONSTRUIRE TOUT et reconstruire individuellement

CHECKPOINT
GO
ALTER INDEX ALL ON IndexTest REBUILD

SELECT *
FROM sys.fn_dblog(NULL,NULL)
WHERE Operation = 'LOP_COMMIT_XACT'
OR Operation = 'LOP_BEGIN_XACT'
GO

CHECKPOINT
GO
ALTER INDEX CIX_IndexTest_ID ON IndexTest REBUILD
ALTER INDEX IX_IndexTest_a ON IndexTest REBUILD
ALTER INDEX IX_IndexTest_b ON IndexTest REBUILD

SELECT *
FROM sys.fn_dblog(NULL,NULL)
WHERE Operation = 'LOP_COMMIT_XACT'
OR Operation = 'LOP_BEGIN_XACT'
GO

Notez que la première transaction ouverte (ID de transaction 0000: 000002fa pour moi) n'est pas validée jusqu'à la fin de la RECONSTRUCTION TOUT, mais pour les reconstructions index par index, elles sont validées successivement.

Forrest
la source
Wow, merci pour la réponse vraiment détaillée! C'est une excellente façon de voir ce qui se passe sous le capot, pour ainsi dire.
Google Fail
Joliment expliqué.
Ramakant Dadhichi
4

En l'état, il s'agit d'une transaction unique.

Pedro Lopes
la source
6
Bienvenue sur DBA.SE! En général, les meilleures réponses ne sont pas de simples affirmations, mais sont étayées par des informations provenant de la documentation ou des articles, ou (souvent encore mieux) une expérience personnelle prouvant la réponse énoncée. Pouvez-vous développer votre réponse, pour fournir ce type de soutien?
RDFozz
2
@RDFozz Fair comment, mais avez-vous regardé le profil de Pedro ? L'accès au code source peut probablement être considéré comme faisant plus autorité que l'expérience personnelle ou la documentation. :-)
Aaron Bertrand
3
@AaronBertrand - Je l'avoue, je ne l'ai pas fait. Je penserais certainement que faire partie de l'équipe SQL Server serait effectivement admissible. Pourtant, cela vaut la peine de faire référence à cela dans la réponse. +1, en tout cas.
RDFozz
3

La question est triviale pour une reconstruction hors ligne . Bien sûr, il s'agit d'une seule transaction. Imaginez les ravages qui s'ensuivraient si l'opération divisait chaque index en sa propre transaction, car elle devrait libérer les verrous lors de la validation , puis les réacquérir. Alors que le verrou critique de table SCH-M a été libéré, les index peuvent être supprimés et de nouveaux index peuvent être créés, comment l'instruction traiterait-elle de tels cas? Sans oublier que la table peut être supprimée, voire recréée entre les deux transactions! Y compris le cas où la table est supprimée et une table différente est créée avec le même identifiant d'objet (oui, cela peut arriver) ...

Que faire si vous augmentez la question pour dire ce qui se passe si la reconstruction d'index est une reconstruction en ligne ? S'agit-il d'une seule transaction ou de plusieurs? La réponse est complexe, car plusieurs transactions internes sont en fait impliquées . Cependant, le point clé est qu'il existe une transaction d'archivage globale qui couvre toute l'opération (l'instruction ALTER) et cela épingle le journal en place (ne peut pas être tronqué), donc l'opération doit être planifiée en conséquence pour permettre ~ 1,6x de données taille pour le mode de récupération FULL, ou taille de données 0,2x pour le mode BULK_LOGGED / SIMPLE. Voir le papier lié pour plus de détails.

Vous pouvez dire que la génération hors ligne n'utilise pas les mêmes transactions internes que le mode en ligne et divise l'opération? Les problèmes que j'ai mentionnés à propos de la table étant modifiée / supprimée entre les opérations d'index individuelles (c'est-à-dire la `` stabilité du schéma '' de la table) nécessiteraient toujours une transaction englobante qui contient un SCH-S sur la table pendant toute la durée de l'instruction. Étant donné que cette transaction doit également contenir le SCH-S pendant la récupération, elle doit être enregistrée et, en tant que tel, un enregistrement de journal BEGIN XACT épinglera le journal et empêchera la troncature pendant toute la durée de l'instruction. Je sais que ce problème particulier a été résolu dans le délai SQL 2016-2017 (en raison de problèmes de taille de journal SQL Azure), mais je ne suis pas sûr de la progression . On dirait que c'est en aperçu maintenant:La reconstruction d'index en ligne pouvant être reprise est en avant-première publique pour SQL Server 2017 CTP 2.0 .

Remus Rusanu
la source
0

Oui, j'ai eu ce même problème avec une très grande table. Chaque fois que j'émettais ALTER INDEX ALL, le journal des transactions augmentait beaucoup, mais s'il était émis ALTER INDEX individuellement, l'utilisation de l'espace du journal serait plus petite.

LT
la source
0

La réponse précédente de Remus selon laquelle l'indexation en ligne nécessite 1,6 fois la taille de l'index en mode de récupération COMPLÈTE n'est pas correcte. La proportion d'espace de journalisation des transactions requise pour reconstruire un index en ligne sous FULL peut être beaucoup plus élevée et nous avons observé plusieurs fois la taille de l'index, en particulier lorsque l'index en cours de reconstruction est compressé car la journalisation des transactions n'est pas compressée. Cela seul devrait indiquer clairement que la journalisation des transactions lors d'une reconstruction en ligne sous FULL peut être au moins quelques fois la taille de l'index. Ajouter un surcoût d'enregistrement de journal qui n'est pas entièrement documenté par Microsoft mais est souvent estimé à 60 octets par ligne et la taille proportionnelle de la journalisation pendant une reconstruction d'index en ligne sous récupération complète peut être plusieurs fois la taille de l'index en cours de reconstruction, surtout si l'index est compressé

Greg Linwood
la source
-1

Rdfozz est correct, c'est la meilleure façon de décider si votre plus grand index peut être reconstruit en fonction du stockage actuel. Exécutez simplement dm_exec_requestspendant que l'opération se produit (ou SQL Profiler) pour voir si tous les index sont en cours de reconstruction. J'envisagerais également de remplacer le modèle de récupération par un enregistrement en masse. C'est ce que je fais et il y a encore des sauvegardes du journal des transactions pendant la fenêtre. Voir l'article ci-dessous https://technet.microsoft.com/en-us/library/ms191484(v=sql.105).aspx

ADTJOB
la source
2
Notez que l'OP a déclaré que sa base de données utilise déjà le modèle de récupération SIMPLE; cela conserve uniquement les transactions dans le journal suffisamment longtemps pour que les transactions se terminent. Il n'y aurait aucune amélioration s'ils passaient à l'enregistrement en bloc.
RDFozz
Vous avez tout à fait raison. Mes excuses.
ADTJOB