J'ai besoin de réduire ma base de données - je viens de libérer beaucoup d'espace

35

Cette question est posée sous différentes formes ici, mais la question se résume à:

Je sais que réduire une base de données est risqué. Dans ce cas, j'ai supprimé tellement de données et je ne les utiliserai plus jamais.

  • Comment puis-je réduire ma base de données? Quels fichiers dois-je réduire?
  • Quelles devraient être mes considérations en faisant cela?
  • Devrais-je faire quelque chose après?
  • Et si c'est une grande base de données? Puis-je le réduire par incréments plus petits?
Mike Walsh
la source
2
J'ai eu du mal avec cela il y a quelque temps: dba.stackexchange.com/questions/47310/… J'ai essayé de résumer mon expérience dans ma réponse
Csaba Toth

Réponses:

30

Quelques mises en garde initiales:

  1. Il est généralement connu comme une mauvaise pratique à jamais réduire un fichier de base de données de production ou de données (fichiers journaux sont un autre problème que cette question parle). Je conseille aux personnes de ne pas réduire leurs bases de données dans des billets de blog comme celui-ci, où je parle de "redimensionnement" et d'une bonne planification. Je ne suis pas seul ( Paul Randal , Brent Ozar , juste pour fournir quelques liens de plus). La réduction d' un des fragments de fichiers de données ou base de données d' index, est lent et laborieux sur vos ressources, peut être un drain sur votre système et est juste une mauvaise chose à faire, en général
  2. Dans ce cas, nous savons tous que le risque existe, nous sommes prêts à y faire face, mais nous avons libéré beaucoup d'espace dont nous savons que nous n'aurons plus jamais besoin. Dans ce type de cas particulier, l’une des options possibles est donc la réduction du coût.

Si vous avez lu des articles sur les préoccupations et les risques et que vous avez toujours besoin de le réduire, car vous avez libéré beaucoup d'espace, nous espérons que le reste de cette réponse vous aidera. Mais considérez les risques.

Il y a deux approches principales que deux considèrent ici:

1.) Réduire Oui, effectuez la réduction - Pensez à utiliser DBCC SHRINKFILEau lieu de DBCC SHRINKDATABASE, vous contrôlez mieux ce qui est rétréci et comment. Cela va entraîner une dégradation des performances à coup sûr - il est une grande opération à faire beaucoup de IO. Vous pouvez éventuellement vous en tirer avec des réductions de taille répétées jusqu'à une taille cible de plus en plus petite.

Voici l'exemple "A.)" du DBCC SHRINKFILElien ci-dessus . Dans cet exemple, un fichier de données est réduit à une taille cible de 7 Mo. Ce format est un bon moyen de réduire de façon répétitive les délais d'indisponibilité de votre fenêtre. Je ferais cela en testant le développement pour voir à quoi ressemblent les performances et comment augmenter / diminuer l’incrément et pour déterminer le timing attendu en production. Il s'agit d'une opération en ligne - vous pouvez l'exécuter avec des utilisateurs du système accédant à la base de données en cours de réduction, mais les performances risquent de se dégrader, ce qui est presque garanti. Alors surveillez et regardez ce que vous faites sur le serveur, choisissez une fenêtre d'indisponibilité ou une période d'activité plus légère, idéalement.

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

Rappelez-vous toujours que: - chaque fois que vous réduisez, vous fragmentez vos index et vous devez procéder à une reconstruction de l'index si vous souhaitez réduire la taille des morceaux sur une période prolongée. Vous engagez maintenant ce coût à chaque fois si vous ne pouvez pas le faire en une seule fenêtre.

2.) Nouvelle base de données - Vous pouvez créer une nouvelle base de données et y migrer des données. Vous devez scripter la base de données vide et toutes ses clés, index, objets, procs, fonctions, etc., puis y migrer des données. Vous pouvez écrire des scripts pour cela ou utiliser un outil tel que SQL Data Compare de Red Gate ou d’autres fournisseurs proposant des outils similaires. C’est davantage un travail d’installation de votre côté, davantage de développement et de tests, et selon votre environnement, la fenêtre d’indisponibilité peut également s’éjecter, mais constitue une option à envisager.

Lorsque je suis obligé de réduire une base de données Si c'était mon environnement, je laisserais un espace vide dans le fichier de données, car j'aime bien être un gros disque et être prêt pour une croissance future / inattendue. Je serais donc d'accord pour laisser de l'espace si nous supprimions simplement une majorité de cet espace, mais je ne ferais jamais confiance à ceux qui disent "mais ça ne grandira plus jamais" tout en laissant un espace blanc. La route avec laquelle j'irais probablement ( soupir) est l’approche de réduction si j’avais de plus petites fenêtres d’indisponibilité et que je ne voulais pas subir la complexité de la création d’une base de données vide et de la migration de données vers celle-ci. Donc, je le réduirais un tas de fois de manière incrémentielle (en fonction du nombre de fois que je pensais devoir le faire en fonction de mes tests en dev et de la taille souhaitée. En choisissant progressivement une taille de fichier plus petite), puis en reconstruisant les index .. Et puis je ' d jamais dire à personne que je réduis ma base de données ;-)

Mike Walsh
la source
1
J'ajoute le cas particulier suivant: si vous supprimez un grand nombre de données d'un segment de mémoire (en particulier du milieu de celui-ci), vous ne pourrez pas récupérer cet espace tant que vous n'aurez pas ajouté d'index clusterisé (espérons-le pour toujours), puis déposez l’index clusterisé après (en le retournant en tas). Bien sûr, si le segment de mémoire est tronqué régulièrement, aucun problème. Mais encore à noter.
Jonathan Fite
Quelqu'un peut-il expliquer l'implication de NOTRUNCATE AND TRUNCATEONLY, apparemment ce dernier ne réorganise pas les pages et ne provoque donc pas de fragmentation d'index?
David Garcia
4
  1. Comment puis-je réduire ma base de données? Quels fichiers dois-je réduire? : Vous pouvez réduire les fichiers individuellement avec la DBCC SHRINKFILEcommande que vous mentionnez. Cela dépend de votre serveur du nombre de fichiers de votre base de données. Une base de données simple a un fichier de base de données et un fichier de journal des transactions.
  2. Quelles devraient être mes considérations en faisant cela?: la réduction affecte votre fragmentation d’index, voir 3ème point. Notez également que vous ne souhaitez pas réduire le fichier de base de données à une taille aussi minime que possible, car dans un environnement réel, il s'agira néanmoins d'une croissance. Je voudrais donc ajuster la taille (dans votre exemple, vous avez donné 7 mégaoctets) de manière à laisser 10 à 20% d’espace libre dans le fichier de base de données, car il sera de toute façon rempli dans l’environnement de production, et vous pourrez sauver certains cycles de croissance automatique de cette façon. Donc, le nombre réel nécessite un calcul minutieux. Notez également que la "grande perte d'espace" que vous avez effectuée alourdirait davantage le fichier journal des transactions que l'espace que vous aviez gagné dans le fichier de base de données. En outre, le gain d'espace réel que vous pouvez expérimenter sera inférieur à ce que vous attendez mathématiquement! Alors disons que vous avez mathématiquement libéré 12 concerts,
  3. Devrais-je faire quelque chose après? : Comme je l'ai mentionné précédemment, vous souhaitez réindexer les index dont la fragmentation a été déformée à la suite des modifications apportées par SHRINK. Je n'ai pas suffisamment expérimenté si vous devez faire quelque chose de spécial en matière de statistiques sur les requêtes.
  4. Et si c'est une grande base de données? Puis-je le réduire par incréments plus petits? L'opération SHRINK peut être interrompue à tout moment et vous pouvez continuer plus tard. Je conseillerais de le faire sur une base de données hors ligne si possible. En interrompant et en continuant, cela ferait avancer la même taille de rétrécissement. Théoriquement, vous pouvez réduire l'incrément par incréments plus petits en spécifiant une taille cible moins étroite au lieu de 7 mégaoctets, mais je dirais que si vous l'exécutez en production, essayez-le simplement une fois. Comme vous le voyez, il existe des problèmes de fragmentation d'index et de croissance possible du journal des transactions. Donc, je passerais par là juste une fois.

Nous savons tous qu'il n'est pas conseillé de faire SHRINK régulièrement de toute façon. J'essaie de laisser de côté tous les avertissements et dénis que vous connaissez probablement de toute façon. Faites une sauvegarde et ne le faites pas à la maison si possible :)

Bonus: dans l'environnement de réplication, si vous effectuez cette opération sur la base de données de l'éditeur, les bases de données des abonnés ne seront pas réduites (ce qui peut poser un problème de taille car il s'agit d'éditions Express).

Enfin, mon script de réindexation:

USE YourDBName

DECLARE @TbName VARCHAR(255)
DECLARE @FullTbName VARCHAR(255)
DECLARE @IxName VARCHAR(255)
DECLARE myCursor CURSOR FOR
    SELECT OBJECT_NAME(dmi.object_id) AS TableName,i.name AS IndexName
    FROM sys.dm_db_index_physical_stats(14, NULL, NULL, NULL , 'LIMITED') dmi
    JOIN  sys.indexes i on dmi.object_id = i.object_id and dmi.index_id = i.index_id
    WHERE avg_fragmentation_in_percent > 30
    ORDER BY avg_fragmentation_in_percent
OPEN myCursor
FETCH NEXT FROM myCursor INTO @TbName, @ixName
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'dba' AND TABLE_NAME = @TbName)
BEGIN
        SET @FullTbName = 'dba.' + @TbName
        IF (@ixName IS NULL)
        BEGIN
            PRINT 'Reindexing Table ' + @FullTbName
            DBCC DBREINDEX(@FullTbName, '', 0)
        END
        ELSE
        BEGIN
             PRINT 'Reindexing Table ' + @FullTbName + ', Index ' + @IxName
             DBCC DBREINDEX(@FullTbName, @IxName, 0)
        END
    END
    FETCH NEXT FROM myCursor INTO @TbName, @ixName
END
CLOSE myCursor
DEALLOCATE myCursor

La seule variable dans ceci est la 14, qui peut être obtenue en émettant select DB_ID('YourDBName'), et le script suppose que vous n'êtes intéressé que par les tables du schéma dba. *.

Csaba Toth
la source
2
Pour la reconstruction d'index, notez que DBREINDEX est déconseillé dans SQL 2005. Plutôt que le script volumineux avec des curseurs, vous pouvez simplement utiliser: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON? REBUILD" J'espère que cela aidera quelqu'un.
KISS
2

Vous avez entendu tous les avertissements concernant la réduction des bases de données et ils sont tous vrais. Cela fragmentera vos index et, en général, gâchera votre base de données et ne devrait pas être fait sur un système de production.

Cependant, je le fais généralement chaque semaine lorsque je restaure une sauvegarde sur mon poste de travail en raison de l'espace disponible sur mon lecteur SSD. Remarquez que je n'ai pas écrit ce script mais que je l'ai trouvé il y a des années. Sur d’autres bases de données [250 Go], j’ai créé un package SSIS qui transfèrera les tables dont j’ai besoin, puis recrée les index pour cette sensation d’indexation si nouvelle.

DECLARE @DBFileName SYSNAME

DECLARE @TargetFreeMB INT

DECLARE @ShrinkIncrementMB INT

SET @DBFileName = 'Set Name of Database file to shrink'

-- Set Desired file free space in MB after shrink

SET @TargetFreeMB = 500
-- Set Increment to shrink file by in MB
SET @ShrinkIncrementMB = 100

SELECT [FileSizeMB] = convert(NUMERIC(10, 2),
round(a.size / 128., 2)),

[UsedSpaceMB] = convert(NUMERIC(10, 2),

round(fileproperty(a.NAME, 'SpaceUsed') / 128., 2)),

[UnusedSpaceMB] = convert(NUMERIC(10, 2),

round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2)),

[DBFileName] = a.NAME

FROM sysfiles a

DECLARE @sql VARCHAR(8000)
DECLARE @SizeMB INT
DECLARE @UsedMB INT

SELECT @SizeMB = size / 128.
FROM sysfiles
WHERE NAME = @DBFileName

SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

SELECT [StartFileSize] = @SizeMB
    ,[StartUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

WHILE @SizeMB > @UsedMB + @TargetFreeMB + @ShrinkIncrementMB

BEGIN
    SET @sql = 'dbcc shrinkfile ( ' + @DBFileName + ', ' + convert(VARCHAR(20), @SizeMB - @ShrinkIncrementMB) + ' ) '

    PRINT 'Start ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    EXEC (@sql)

    PRINT 'Done ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    SELECT @SizeMB = size / 128.
    FROM sysfiles
    WHERE NAME = @DBFileName

    SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

    SELECT [FileSize] = @SizeMB
        ,[UsedSpace] = @UsedMB
        ,[DBFileName] = @DBFileName
END

SELECT [EndFileSize] = @SizeMB
    ,[EndUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

SELECT [FileSizeMB] = convert(NUMERIC(10, 2), round(a.size / 128., 2))

    ,[UsedSpaceMB] = convert(NUMERIC(10, 2), round(fileproperty a.NAME, 'SpaceUsed') / 128., 2))

,[UnusedSpaceMB] = convert(NUMERIC(10, 2), round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2))

,[DBFileName] = a.NAME

FROM sysfiles a
utilisateur1207758
la source
1

Cette citation ci-dessous provient directement de Microsoft (s’applique aux versions 2008-2016) et donne des indications sur la question de savoir si / quand et comment utiliser cette DBCC SHRINKFILEcommande.

https://msdn.microsoft.com/en-us/library/ms189493.aspx

Les meilleures pratiques

Prenez en compte les informations suivantes lorsque vous prévoyez de réduire un fichier:

  • Une opération de réduction est plus efficace après une opération qui crée beaucoup d'espace inutilisé, telle qu'une opération tronquer une table ou supprimer une table.
  • La plupart des bases de données requièrent de l’espace libre pour les opérations quotidiennes courantes. Si vous réduisez une base de données à plusieurs reprises et remarquez que sa taille augmente à nouveau, cela indique que l'espace qui a été réduit est requis pour les opérations courantes. Dans ces cas, la réduction répétée de la base de données est une opération perdue.
  • Une opération de réduction ne préserve pas l'état de fragmentation des index de la base de données et augmente généralement la fragmentation dans une certaine mesure. C'est une autre raison pour ne pas réduire la base de données à plusieurs reprises.
  • Réduisez plusieurs fichiers dans la même base de données de manière séquentielle plutôt que concurrente. Les conflits sur les tables système peuvent entraîner des retards dus au blocage.
g2server
la source