web-dev-qa-db-fra.com

Comment réduire rapidement tous les fichiers pour toutes les bases de données?

Dans SQL Server (2008 dans ce cas), comment puis-je réduire rapidement tous les fichiers, à la fois le journal et les données, pour toutes les bases de données d'une instance? Je pourrais passer par SSMS et cliquer droit chacun et choisir Tâches -> Rétrécir, mais je cherche quelque chose de plus rapide.

J'ai écrit quelques scripts "Créer une base de données" et j'ai oublié qu'ils avaient des tailles gonflées pour les valeurs par défaut, et n'ont pas besoin de beaucoup d'espace réservé pour ces fichiers sur ce projet.

47
jcolebrand

Lorsque vous effectuez "Tâches -> Rétrécir" à partir de l'interface graphique, il émet en fait un DBCC SHRINKDATABASE commande dans les coulisses. Essayez-le. Lorsque la boîte de dialogue s'affiche, ne cliquez pas sur le bouton "OK". Cliquez plutôt sur le bouton "Script". Vous verrez la commande dans une fenêtre de requête. Combinez cela avec une requête sur sys.databases (laissez de côté master et msdb), et vous pouvez créer un script pour réduire toutes les bases de données.

Par exemple (extrait du commentaire de jcolebrand):

SELECT 
      'USE [' + d.name + N']' + CHAR(13) + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 
FROM 
         sys.master_files mf 
    JOIN sys.databases d 
        ON mf.database_id = d.database_id 
WHERE d.database_id > 4;

Copiez la sortie de cette requête et exécutez-la pour réduire tous vos fichiers.

59
Larry Coleman

Que diriez-vous d'une seule ligne de déclaration SQL?

Veuillez lire ce article de blog très intéressant avant d'exécuter l'instruction sql suivante.

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'
22
CoderHawk

DBCC SHRINKDB (et son cousin SHRINKFILE) sont extrêmement lents, car il y a beaucoup d'exécution à thread unique dans ce code.

Un moyen beaucoup plus rapide de réduire un fichier de base de données est le suivant:

  • Allouer un nouveau groupe de fichiers à la base de données
  • Rendez ce groupe de fichiers aussi grand qu'il doit l'être (utilisez sp_spaceused pour déterminer la taille)
  • Reconstruisez tous les index de ce nouveau groupe de fichiers
  • Supprimer l'ancien groupe de fichiers

Étant donné que les reconstructions d'index sont massivement parallèles, cette technique entraîne souvent une réduction beaucoup plus rapide de la base de données. Bien sûr, cela nécessite que vous ayez un peu d'espace supplémentaire pour le nouveau groupe de fichiers pendant le processus. Cependant, vous n'avez besoin que de suffisamment d'espace dans le nouveau groupe de fichiers pour contenir le plus grand groupe de fichiers de l'instance (car vous récupérerez de l'espace au fur et à mesure).

Cette technique a également l'avantage supplémentaire de défragmenter vos index dans le processus.

15
Thomas Kejser

J'ai ajusté un peu la requête pour ne réduire que le journal tel qu'il est demandé:

set nocount on  
SELECT 
      'USE [' + d.name + N']' + CHAR(13) + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 
FROM 
         sys.master_files mf 
    JOIN sys.databases d 
        ON mf.database_id = d.database_id 
WHERE d.database_id > 4 and mf.type_desc = 'LOG'
13
Frankachela

Le code ci-dessous, obtenez une liste des bases de données non système, définissez la base de données en lecture seule, puis réduisez le fichier. J'ai conservé ce code dans quelques boîtes SQL Server à l'aide du travail de l'Agent SQL, où l'espace est toujours un problème. Le samedi/dimanche soir chaque semaine, il commence à fonctionner et réduit toutes les bases de données en quelques heures (selon la taille des bases de données).

declare @db varchar(255)
declare c cursor for
select name from sys.databases where is_read_only=0 and state=0
  and name not in ('master','model','tempdb','msdb')
open c
fetch c into @db
while @@fetch_status=0
begin
  exec SP_dboption @db,'trunc. log on chkpt.','true' 
  DBCC shrinkdatabase (@db)
  fetch next from c into @db
end
close c
deallocate c

Celui-ci étend la réponse ci-dessus, en utilisant un curseur pour parcourir les instructions SQL une par une. Ce n'est pas aussi court que la réponse d'Emrah, mais cela permet une logique supplémentaire dans la boucle while du curseur.

SELECT 
    'USE [' 
    + databases.name + N']' 
    + CHAR(13) 
    + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' 
    + masterFiles.name 
    + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) 
    + CHAR(10) 
    + CHAR(13) 
    + CHAR(10)                                                                  AS sqlCommand
INTO
    #shrinkCommands
FROM 
    [sys].[master_files] masterFiles 
    INNER JOIN [sys].[databases] databases ON masterFiles.database_id = databases.database_id 
WHERE 
    databases.database_id > 4; -- Exclude system DBs


DECLARE iterationCursor CURSOR

FOR
    SELECT 
        sqlCommand 
    FROM 
        #shrinkCommands

OPEN iterationCursor

DECLARE @sqlStatement varchar(max)

FETCH NEXT FROM iterationCursor INTO @sqlStatement

WHILE (@@FETCH_STATUS = 0)
BEGIN
    EXEC(@sqlStatement)
    FETCH NEXT FROM iterationCursor INTO @sqlStatement
END

-- Clean up
CLOSE iterationCursor
DEALLOCATE iterationCursor
DROP TABLE #shrinkCommands
0
Alistair

Rétrécir tous les fichiers journaux sauf master, model, msdb:

EXEC sp_MSforeachdb '
DECLARE @sqlcommand nvarchar (500)
IF ''?'' NOT IN (''master'', ''model'', ''msdb'')
BEGIN
USE [?]
SELECT @sqlcommand = ''DBCC SHRINKFILE (N'''''' + 
name
FROM [sys].[database_files]
WHERE type_desc = ''LOG''
SELECT @sqlcommand = @sqlcommand + '''''' , 0)''
EXEC sp_executesql @sqlcommand
END'
0
Emrah Saglam

Nous pouvons répéter dynamiquement SHRINKDB et SHRINKFILE pour toutes les bases de données:

while @DBID<=@MaxDBID
begin
  -- Used Dynamic SQL for all databases.
  Set @SQL ='Use '+@DBName+ ' '+Char(10)
  Set @SQL += 'DBCC SHRINKFILE('+@Filename+',5)' +Char(10)
  Set @SQL += 'DBCC SHRINKDATABASE('+@DBName+')'+Char(10)

  --#6 Increment DBid for looping over all databases
  Set @DBID = @DBID+1
  Select @DBName = DBName, @Filename=DBFileName from #DBNames where [dbid] = @DBID and type_Desc = 'LOG'
  Print (@SQL)
  Exec (@SQL)
end

Vous pouvez trouver des détails dans cet article .

0
Anup Kulkarni