web-dev-qa-db-fra.com

Rétrécissez plusieurs fichiers de base de données à l'aide de sp_msforeachdb

Nous avons récemment effacé les anciennes données de notre base de données de production. La base de données est 3 TB avec 1.4 TB vide ceci, cependant, pose un problème sur l'instance de développement et d'assurance qualité, car nous n'utilisons pas d'espace en disposant de 6 à 8 bases de données avec 1.4 TB espace vide, en particulier avec les contraintes d'espace, nous avons sur le développement. Je souhaite configurer un travail pour réduire les bases de données de développement à l'aide du code ci-dessous.

EXEC sp_MSForEachDB ' USE [?]; DBCC SHRINKFILE  (''?'' , 10)' 

EXEC sp_MSForEachDB ' USE [?]; DBCC SHRINKFILE (''?'' , 0, TRUNCATEONLY)' 

Je reçois l'erreur suivante "Impossible de localiser le fichier" Test "pour la base de données" Test "dans sys.database_files. Le fichier n'existe pas ou n'a pas été supprimé." La base de données contient plusieurs fichiers de données. Comment pourrais-je améliorer mon code pour accueillir les fichiers de données multiples.

3
Vorster

@Sp_blitzerik a correctement identifié le problème, mais je proposerais une solution différente: utilisez un script ponctuel qui crée vos déclarations SHRINKFILE, vérifiez-les pour la santé mentale, puis exécutez-les manuellement. Ou mettez-les dans votre poste d'agent:

SELECT  dbname = DB_NAME(),
        file_name = name, 
        TotalMB = CONVERT(decimal(12,1),size/128.0),
        UsedMB = CONVERT(decimal(12,1),FILEPROPERTY(name,'SpaceUsed')/128.0),
        FreeMB = CONVERT(decimal(12,1),(size - FILEPROPERTY(name,'SpaceUsed'))/128.0),
        Command = CONCAT('USE ', DB_NAME(), '; DBCC SHRINKFILE (name = ',
              [name], ', size = ', 
              convert(int,round(1.15 * FILEPROPERTY(name,'SpaceUsed')/128,-1)), 'MB)')
 FROM sys.database_files WITH (NOLOCK)
 WHERE type_desc = 'ROWS'
 ORDER BY file_id;

Exécutez ceci une fois de chaque base de données, il doit renvoyer la taille totale et utilisée pour chaque fichier de données (il saute les fichiers journaux, vous pouvez les réduire instantanément à la main) et un exemple SHRINKFILE Déclaration qui vous donne une cible de 15% d'espace libre dans le fichier, calculée à partir de l'espace actuel utilisé:

USE myDB; DBCC SHRINKFILE (name = myDBData, size = 148910MB)

Vous devrez vérifier les résultats pour la santé mentale, si le fichier déjà a moins de 15% d'espace libre, alors l'instruction SHRINKFILE _ Spécifiera une plus grande taille qu'elle n'a actuellement pas Il (c'est déjà assez petit).

Une fois que vous avez rétréci tous les fichiers de données, choisissez une taille de la cible pour chaque fichier log (J'utilise généralement 10-25% de la taille du fichier de données) et rétrécissez ceux à la main. Cela peut dépendre du modèle de récupération, ainsi que de la quantité d'activité de ces DBS dans cet environnement.

2
BradC

La marque d'interrogation évaluera au nom de la base de données et non au nom de fichier que vous essayez de réduire.

Par exemple:

EXEC master.sys.sp_MSforeachdb ' USE [?]; PRINT N''?''; '; 

Retournera (sur mon serveur)

master
tempdb
model
msdb
SUPERUSER
StackOverflow
StackOverflow_CS
Crap
DBAtools
StackOverflow2010
SUPERUSER_CX
ಠ_ಠ
StackOverflow2010ಠ_ಠ

DBCC strinkfile ne prend pas cela comme un argument:

DBCC Shrinkfile (
[.____] {Nom de fichier | file_id}
{ [ , FICHIER VIDE ]
[.____] | [[ cible_size] [ {NOTRONCATE | Troncatetonly}]]
[.____]}) [avec no_infomsgs]

Si vous n'avez qu'un fichier .MDF et un .ldf, vous pouvez (probablement, bien que pas certainement) remplacer votre code avec:

EXEC sp_MSForEachDB ' USE [?]; DBCC SHRINKFILE  (1 , 10)' 

EXEC sp_MSForEachDB ' USE [?]; DBCC SHRINKFILE (2 , 0, TRUNCATEONLY)' 

Plus de code verbeux pour rechercher des identifiants de fichier, etc. est laissé comme un exercice au lecteur.

Si vous voulez simplement rétrécir le tout, utilisez-le DBCC Shrinkdatabase à la place. Cela prend un nom de base de données et fonctionnera avec votre code d'origine.

DBCC StrinkDatabase (Nom de base de données | Database_ID | 0
[.____] [ cible_percent]
[.____] [ {NOTRONCATE | Troncatetonly}]) [avec no_infomsgs]

Bien sûr, cela peut causer toutes sortes de problèmes , et je ne voudrais pas le faire.

4
Erik Darling

@Bradc Voici comment j'ai adapté votre code suggéré

CREATE TABLE #ShrinkFile
(
DBName sysname,
File_Name sysname,
TotalMB decimal (18,2),
UsedMB decimal (18,2),
FreeMB decimal (18,2),
Command nvarchar(MAX)
) 
EXEC master.sys.sp_MSforeachdb ' USE [?]; 
    Insert Into #ShrinkFile (DBName, File_Name, TotalMB, UsedMB, FreeMB, 
Command)
    SELECT  dbname = DB_NAME(),
    file_name = name, 
    TotalMB = CONVERT(decimal(12,1),size/128.0),
    UsedMB = CONVERT(decimal(12,1),FILEPROPERTY(name,''SpaceUsed'')/128.0),
    FreeMB = CONVERT(decimal(12,1),(size - 
    FILEPROPERTY(name,''SpaceUsed''))/128.0),
    Command = CONCAT(''USE '', DB_NAME(), ''; DBCC SHRINKFILE (name = '',
          [name], '', size = '', 
          convert(int,round(1.15 * 
FILEPROPERTY(name,''SpaceUsed'')/128,-1)), ''MB)'')
FROM sys.database_files WITH (NOLOCK)
WHERE type_desc = ''ROWS''
ORDER BY file_id;'

IF EXISTS (SELECT * FROM  #ShrinkFile WHERE FreeMB > 1000)
BEGIN
   DECLARE @SQLText nvarchar(max)
   DECLARE Shrink_cursor CURSOR FOR 
   SELECT DISTINCT Command FROM #ShrinkFile
   WHERE FreeMB > 1000

   OPEN Shrink_cursor  
   FETCH NEXT FROM Shrink_cursor INTO @SQLText  

   WHILE @@FETCH_STATUS = 0  
   BEGIN  
        EXEC (@SQLText)
        FETCH NEXT FROM Shrink_cursor INTO @SQLText 
   END 

 CLOSE Shrink_cursor  
 DEALLOCATE Shrink_cursor 
 END

 DROP TABLE #ShrinkFile
0
Vorster