web-dev-qa-db-ja.com

sp_MSForEachDBを使用して複数のデータベースファイルを圧縮する

最近、本番データベースから古いデータを消去しました。データベースは3 TB with 1.4 TB emptyですが、6〜8個のデータベースを使用してスペースを利用していないため、開発とQAインスタンスに問題が発生します。 1.4 TB空のスペース、特に開発時にスペースの制約がある場合。以下のコードを使用して開発データベースを縮小するジョブをセットアップしたい

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

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

「sys.database_filesでデータベース 'Test'のファイル 'Test'を見つけることができませんでした。ファイルが存在しないか、削除されました。」というエラーが発生します。データベースには複数のデータファイルがあります。複数のデータファイルに対応できるようにコードを改善するにはどうすればよいですか。

3
Vorster

@sp_BlitzErikは問題を正しく識別していますが、別の解決策を提案します:createsSHRINKFILEステートメントを1回限りのスクリプトで使用し、正常性を確認してから手動で実行するか、エージェントジョブ:

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;

これを各データベースから1回実行すると、各データファイルの合計および使用済みサイズが返されます(ログファイルはスキップされ、後で手作業で即座に縮小できます)、およびSHRINKFILEステートメントの例現在使用されているスペースから計算された、ファイル内の15%の空きスペースの目標:

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

ファイルalreadyの空き領域が15%未満の場合は、結果の健全性を確認する必要があります。その場合、SHRINKFILEステートメントは現在のサイズよりも大きいサイズを指定するため、スキップします(すでに小さい)足りる)。

すべてのデータファイルを縮小したら、各logファイルのターゲットサイズを選択し(通常、データファイルサイズの10〜25%を使用します)、手動で縮小します。これは、復旧モデルと、これらのデータベースがその環境で取得するアクティビティの量によって異なる場合があります。

2
BradC

疑問符は、縮小しようとしているファイル名ではなく、データベース名に評価されます。

例えば:

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

戻ります(私のサーバー上)

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

DBCC SHRINKFILE はそれを引数として取りません:

DBCC SHRINKFILE(
{file_name | file_id}
{[、EMPTYFILE]
| [[、target_size] [、{NOTRUNCATE |切り捨て}]]
})[WITH NO_INFOMSGS付き]

.mdfと.ldfしかない場合は、(間違いではありませんが)コードを次のように置き換えることができます。

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

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

ファイルIDなどを検索するためのより詳細なコードは、読者への課題として残されています。

全体を縮小したい場合は、代わりに DBCC SHRINKDATABASE を使用します。これはデータベース名を取り、元のコードで動作します。

DBCC SHRINKDATABASE(database_name | database_id | 0
[、target_percent]
[、{NOTRUNCATE | TRUNCATEONLY}])[NO_INFOMSGS付き]

もちろん、これは あらゆる種類の問題 を引き起こす可能性があり、私はそれをしたくありません。

4
Erik Darling

@BradCこれは私があなたの提案されたコードをどのように適応させたかです

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