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

47

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

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

jcolebrand
la source

Réponses:

55

Lorsque vous effectuez "Tâches -> Réduire" à partir de l'interface graphique, une DBCC SHRINKDATABASEcommande est exécutée dans les coulisses. L'essayer Lorsque la boîte de dialogue apparaît, ne cliquez pas sur le bouton "OK". Au lieu de cela, cliquez sur le bouton "Script". Vous verrez la commande dans une fenêtre de requête. Combinez cela avec une requête sur sys.databases (ignore master et msdb) et vous pouvez créer un script pour réduire toutes les bases de données.

Par exemple (tiré 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 le résultat de cette requête et exécutez-le pour réduire tous vos fichiers.

Larry Coleman
la source
1
Ok, je pense que j'ai ce que je veux (moche mais fait juste ce dont j'ai besoin) 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 > 4Mais trouver ça m'a posé un nouveau problème. Off pour poster une autre question.
jcolebrand
Sérieusement. Découvrez la réponse de @ Sandy. les sp_MSForEachDB (il y a aussi un sproc "table" aussi) sont extrêmement utiles
swasheck
3
Et voici le rappel obligatoire à tous ceux qui lisent ceci: Réduire votre base de données est dangereux.
Nick Chammas
1
filtrer Offline DB le rendrait encore meilleur. :-)
TiloBunt
1
Convenu avec @TiloBunt, la condition entière est meilleure, car WHERE d.database_id> 4 AND d.state_desc = 'ONLINE';
Mauro
23

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

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

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'
CoderHawk
la source
6
Une seule ligne de code n'est pas nécessairement préférable si elle risque de ne pas fonctionner correctement. Veuillez également lire ces articles, car sp_msforeachdb peut ignorer des bases de données et ne pas vous avertir: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… et mssqltips.com/sqlservertip/2201/…
Aaron Bertrand
15

DBCC SHRINKDB (et son cousin SHRINKFILE) sont extrêmement lents, car ce code contient beaucoup d’exécutions à un seul thread.

Voici un moyen beaucoup plus rapide de réduire un fichier de base de données:

  • Allouer un nouveau groupe de fichiers à la base de données
  • Rendez ce groupe de fichiers aussi grand que nécessaire (utilisez sp_spaceusedpour déterminer la taille)
  • Reconstruire tous les index sur ce nouveau groupe de fichiers
  • Supprimer l'ancien groupe de fichiers

Comme 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 disposiez d'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 allez récupérer de l'espace au fur et à mesure).

Cette technique présente également l’avantage supplémentaire de défragmenter vos index au cours du processus.

Thomas Kejser
la source
Vous avez oublié une partie importante. La reconstruction des index ne déplace rien d'autre, y compris les procédures stockées, les vues, les fonctions, les synonymes, les tas, etc.
Jeff Moden
Et ceux-ci ne prennent aucune place qui devrait vous intéresser. Ils doivent aussi résider dans le groupe de fichiers PRIMARY, vous ne pouvez pas vraiment les déplacer (et vous ne devriez pas non plus le faire)
Thomas Kejser
13

J'ai un peu optimisé la requête pour réduire uniquement 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'
Frankachela
la source
"
Réduire
2
Je cherchais ceci et étais sur le point de doubler mes messages lorsque j'ai vu votre réponse. Pas de réponse directe, mais TRÈS pertinente et pertinente pour mon cas.
Gomibushi
2

Le code ci-dessous, obtenez une liste des bases de données non système, définissez la base de données sur lecture seule, puis réduisez le fichier. J'ai conservé ce code dans quelques boîtes SQL Server à l'aide du travail d'agent SQL, où l'espace est toujours un problème. Chaque nuit, les samedis et dimanches, il commence à fonctionner et réduit toutes les bases de données en quelques heures (en fonction de 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
Muhammad Sharjeel Ahsan
la source
0

Réduisez tous les fichiers journaux sauf le maître, le modèle et la 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'
Emrah Saglam
la source
0

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
Alistair
la source
0

Nous pouvons répéter SHRINKDBet SHRINKFILEpour toutes les bases de données de manière dynamique:

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 .

Anup Kulkarni
la source