Cette question est posée sous différentes formes ici mais la question se résume à:
Je sais que la réduction d'une base de données est risquée. Dans ce cas, j'ai supprimé tellement de données et je ne les utiliserai plus jamais.
Quelques mises en garde initiales:
Si vous avez lu les inquiétudes et les risques et que vous devez encore faire cette réduction parce que vous avez libéré une quantité d'espace significative, j'espère que le reste de cette réponse vous aidera. Mais tenez compte des risques.
Il existe deux approches principales que deux considèrent ici:
1.) Rétrécir Oui, faire le rétrécissement réel - Pensez à utiliser DBCC SHRINKFILE
au lieu de DBCC SHRINKDATABASE
, vous avez plus de contrôle sur ce qui se rétrécit et comment. Cela entraînera une certaine dégradation des performances à coup sûr - c'est une grande opération qui fait beaucoup d'E/S. Vous pouvez potentiellement s'en tirer avec des rétrécissements répétés à une taille cible qui devient progressivement plus petite.
Il s'agit de l'exemple "A.)" ci-dessus DBCC SHRINKFILE
link .. Un fichier de données est réduit à une taille cible de 7 Mo dans cet exemple. Ce format est un bon moyen de rétrécir de façon répétée si votre fenêtre d'indisponibilité le permet. Je le ferais en testant le développement pour voir à quoi ressemblent les performances et à quel niveau vous pouvez aller d'un incrément et pour déterminer le calendrier attendu de la 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 il y aura une dégradation des performances, presque garantie. Surveillez et regardez et voyez 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: - chaque fois que vous réduisez, vous fragmentez vos index et devez faire une reconstruction d'index si vous prévoyez de réduire en morceaux sur une période de temps prolongée . Vous engagez maintenant ce coût à chaque fois si vous ne pouvez pas tout faire dans une seule fenêtre.
2.) Nouvelle base de données - Vous pourriez créer une nouvelle base de données et y migrer des données. Vous devez créer un script pour la base de données vide et toutes ses clés, index, objets, procs, fonctions, etc., puis migrer les données vers celle-ci. Vous pouvez écrire des scripts pour cela ou vous pouvez utiliser un outil comme SQL Data Compare de Red Gate ou d'autres fournisseurs avec des outils similaires. C'est plus de travail de configuration de votre côté, plus de développement et de tests, et selon votre environnement, cela peut également faire exploser votre fenêtre d'indisponibilité, mais une option à considérer.
Quand je suis forcé de réduire une base de données Si tel était mon environnement, je chercherais à laisser une foire/grande quantité d'espace blanc dans le fichier de données, car j'aime être un porc de disque et être prêt à une croissance future/inattendue. Donc, je serais d'accord de redonner de l'espace si nous supprimions la majorité de l'espace, mais je ne ferais jamais confiance à ceux qui disent "mais il ne s'agrandira plus" et laisserait toujours - certains un espace blanc. L'itinéraire que j'irais probablement avec ( soupir) est l'approche de rétrécissement si j'avais des fenêtres d'indisponibilité plus petites et que je ne voulais pas encourir la complexité de créer une base de données vide et de migrer des 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 avoir besoin 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 ne dirais jamais à personne que j'ai réduit ma base de données; -)
DBCC SHRINKFILE
Que vous mentionnez. Cela dépend de votre serveur combien de fichiers se compose votre base de données. Une base de données simple possède un fichier de base de données et un fichier journal des transactions.Nous savons tous qu'il n'est pas conseillé de faire du SHRINK régulièrement de toute façon. J'essaie de laisser de côté tous les avertissements et avertissements que vous connaissez probablement de toute façon. Sauvegardez, et ne faites pas cela à la maison si possible :)
Bonus: dans un environnement de réplication, si vous effectuez cette opération sur la base de données de l'éditeur, cela n'entraînera pas la réduction des bases de données des abonnés (ce qui peut avoir le problème de taille car ce sont des é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 ce cas est le 14, qui peut être obtenu en émettant select DB_ID('YourDBName')
, et le script suppose que vous n'êtes intéressé que par les tables du schéma dba. *.
Vous avez entendu tous les avertissements concernant la réduction des bases de données et ils sont tous vrais. Il va fragmenter vos index et, en général, gâcher votre base de données et ne devrait pas être fait sur un système de production.
Mais, je le fais généralement chaque semaine lorsque je restaure une sauvegarde sur mon poste de travail en raison de l'espace sur mon disque SSD. Attention, je n'ai pas écrit ce script mais 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éera les index pour cette sensation d'index si fraîche.
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
Cette citation ci-dessous est directement de Microsoft (s'applique aux versions 2008-2016) et donne des conseils sur si/quand et comment utiliser le DBCC SHRINKFILE
commande.
https://msdn.Microsoft.com/en-us/library/ms189493.aspx
Meilleures pratiques
Tenez compte des 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é, comme une table tronquée ou une opération de suppression de table.
- La plupart des bases de données nécessitent de l'espace libre pour les opérations quotidiennes normales. Si vous réduisez une base de données à plusieurs reprises et remarquez que la taille de la base de données augmente à nouveau, cela indique que l'espace qui a été réduit est requis pour les opérations normales. Dans ces cas, la réduction répétée de la base de données est une opération inutile.
- Une opération de réduction ne préserve pas l'état de fragmentation des index dans la base de données et augmente généralement la fragmentation dans une certaine mesure. C'est une autre raison de ne pas réduire à plusieurs reprises la base de données.
- Rétrécissez plusieurs fichiers dans la même base de données de manière séquentielle au lieu de simultanément. Les conflits sur les tables système peuvent entraîner des retards dus au blocage.