データベースを縮小する必要があります-多くのスペースを解放しました


35

この質問はさまざまな形式でここに尋ねられますが、質問は次のように要約されます。

データベースの縮小は危険を伴うことを知っています。この場合、大量のデータを削除したため、二度と使用しません。

  • データベースを縮小するにはどうすればよいですか?どのファイルを縮小しますか?
  • これを行う際の考慮事項は何ですか?
  • 後は何をすべきですか?
  • 大規模なデータベースの場合はどうなりますか?少しずつ縮小できますか?

2
私はいくつかの時間前にこれで苦労:dba.stackexchange.com/questions/47310/...私は私の答えで私の経験をまとめてみました
チャバ・トス

回答:


30

いくつかの最初の警告:

  1. これは、一般的に最悪の練習として知られ、これまで(ログファイルは別の問題としてある本番データベースやデータファイルを縮小し、この質問についての協議)。このようなブログ投稿では、データベースを縮小しないでください。「適切なサイズ設定」と適切な計画について説明しています。私はそこにいるだけではありません(Paul RandalBrent Ozar、リンクをいくつか提供するだけです)。データファイルまたはデータベースフラグメントインデックスの縮小は、リソースの処理に時間がかかり、面倒であり、システムのドレインになる可能性があり、一般的に悪いことです。
  2. この場合、私たちはリスクが存在することをすべて知っており、それに対処する準備ができていますが、今後必要になることはないとわかっいる多くのスペース解放しましたそのため、この特定の場合-縮小はオプションの1つとして非常に理にかなっています。

懸念事項とリスクについて読んだ後、かなりのスペースを解放したためにこの縮小を行う必要がある場合は、この回答の残りの部分が役立つことを願っています。しかし、リスクを考慮してください。

ここで考慮すべき2つの主なアプローチがあります。

1.)縮小 はい、実際の縮小を行います -のDBCC SHRINKFILE代わりに使用することを検討してくださいDBCC SHRINKDATABASE。縮小する対象と方法をより細かく制御できます。これ確かにパフォーマンスの低下を引き起こします-それは大量のIOを行う大規模な操作です。次第に小さくなるターゲットサイズまで繰り返し縮小することで、潜在的に逃げることができます。

これは、上記のDBCC SHRINKFILEリンクの「A.)」の例です。この例では、データファイルが7MBのターゲットサイズに縮小されています。この形式は、ダウンタイムウィンドウが許す限り繰り返し縮小するのに適した方法です。開発のテストでこれを行い、パフォーマンスがどのように見えるか、増分をどれだけ低く/高くできるかを確認し、本番で予想されるタイミングを決定します。これはオンライン操作です-縮小されているデータベースにアクセスするシステム内のユーザーで実行できますが、パフォーマンスが低下し、ほぼ保証されます。そのため、理想的には、サーバーに対して行っていることを監視および監視し、ダウンタイムウィンドウまたはより軽いアクティビティの期間を選択します。

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

常に覚えておいてください: -縮小するたびにインデックスを断片化し、長期間にわたってチャンクで縮小する場合はインデックスの再構築を行う必要があります。1つのウィンドウですべてを完了できない場合、毎回そのコストが発生します。

2.)新しいデータベース - 新しいデータベースを作成して、そこにデータを移行できます。空のデータベースとそのすべてのキー、インデックス、オブジェクト、プロシージャ、関数などのスクリプトを作成し、データをそこに移行する必要があります。このためのスクリプトを作成することも、Red GateのSQL Data Compareなどのツールまたは同様のツールを持つ他のベンダーを使用することもできます。これはあなたの側でのより多くのセットアップ作業であり、より多くの開発とテストであり、あなたの環境によってはダウンタイムウィンドウを吹き飛ばすかもしれませんが、考慮すべきオプションです。

私はときに強制していますデータベースを縮小するために 、これは私の環境であれば、私はので、私のディスクを独り占めいるようと将来/予想外の成長のために準備されたいデータファイル内の空白の公正/多額の金額を残すように見えると思います。私たちは宇宙の大部分を削除した場合、私は大丈夫寄付スペースバックだろうが、私はそれらが言って「それは再び成長することはありません」と、まだ残して信用したことがなかったので、いくつかの空白を。たぶん行くルート(ため息)は、ダウンタイムウィンドウが小さく、空のDBを作成してそこにデータを移行するという複雑さを避けたい場合の縮小アプローチです。(私は私のdevにテストと希望のサイズに基づいてする必要がありました。徐々に小さいファイルサイズを選択すると思った回数に基づいて)漸増それを倍の束を縮小して、インデックスを再構築...う、私はそう「そして私d誰にも私がデータベースを縮小したとは決して言わない;-)


1
ヒープから大量のデータを(特にヒープの中央から)削除した場合、クラスター化インデックスを追加するまで(できれば永久に)そのスペースを取り戻すことができないという特殊なケースを追加します。その後、クラスター化インデックスを削除します(ヒープに戻します)。もちろん、ヒープが定期的に切り捨てられる場合は心配ありません。しかし、まだ言及する価値があります。
ジョナサン

誰かがNOTRUNCATEとTRUNCATEONLYの意味を説明できますか、明らかに後者はページを再配置しないため、インデックスの断片化を引き起こしませんか?
デビッドガルシア

4
  1. データベースを縮小するにはどうすればよいですか?どのファイルを縮小しますか?DBCC SHRINKFILE言及したコマンドでファイルを個別に縮小できます。データベースのファイル数はサーバーに依存します。単純なデータベースには、1つのデータベースファイルと1つのトランザクションログファイルがあります。
  2. これを行う際の考慮事項は何ですか?:縮小はインデックスの断片化に影響します。3番目のポイントを参照してください。また、実際の環境ではとにかく成長するため、データベースファイルを最小限のサイズに縮小したくないことに注意してください。したがって、データベースファイル内に10%〜20%の空き領域を残すようにサイズを調整します(この例では7メガバイトを指定します)。そのようにして自動成長サイクルを節約します。したがって、実際の数は慎重に計算する必要があります。また、実行した「大きな領域の解放」により、DBファイル内で獲得した領域よりもさらにトランザクションログファイルが大きくなることに注意してください。また、実際に発生する可能性のあるスペースゲインは、数学的に予想されるものよりも少なくなります。そこで、数学的に12ギグを解放したとしましょう。
  3. 後は何をすべきですか?:前述したように、SHRINKの変更の結果として断片化が歪んだインデックスのインデックスを再作成する必要があります。クエリ統計について特別なことをする必要がある場合は、十分に実験していません。
  4. 大規模なデータベースの場合はどうなりますか?少しずつ縮小できますか?SHRINK操作はいつでも中断でき、後で続行できます。可能であれば、オフラインデータベースで実行することをお勧めします。中断して継続することにより、同じサイズの縮小を進めます。理論的には、7メガバイトではなく、より厳密でないターゲットサイズを指定することで、より小さな増分で縮小できますが、実稼働環境で実行している場合は、一度だけ実行してください。ご覧のとおり、インデックスの断片化とトランザクションログの増大の可能性に問題があります。だから私は一度だけこれを経験するだろう。

とにかく定期的にSHRINKを行うことはお勧めできません。とにかくあなたがおそらく知っているすべての警告と免責事項を除外しようとします。バックアップし、可能であれば自宅でこれをしないでください:)

ボーナス:レプリケーション環境では、パブリッシャーデータベースでこれを実行しても、サブスクライバーデータベースが縮小することはありません(Expressエディションであるため、サイズに問題がある可能性があります)。

最後に、インデックス再作成スクリプト:

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

この唯一の変数は14です。これはselectを発行することで取得できDB_ID('YourDBName')、スクリプトはdba。*スキーマのテーブルのみに関心があると想定しています。


2
インデックスの再構築については、DBREINDEXがSQL 2005で非推奨になったことに注意してください。カーソルを使用する巨大なスクリプトではなく、EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON?REBUILD"を使用できます。
キッス

2

データベースの縮小に関するすべての警告を聞いたことがありますが、それらはすべて真実です。これはインデックスを断片化しますが、一般的にはデータベースを破壊するため、本番システムでは実行しないでください。

しかし、私は通常、SSDドライブのスペースが原因でワークステーションにバックアップを復元するときに、週単位でこれを行います。念のため、このスクリプトは書いていませんが、数年前に発見しました。他のデータベース[250 GB]で、必要なテーブルを転送するSSISパッケージを作成し、そのためにインデックスを再作成します。

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

1

以下のこの引用は、Microsoftから直接のものであり(バージョン2008-2016に適用)、DBCC SHRINKFILEコマンドを使用する場合/いつ、どのように使用するかについてのガイダンスを提供します。

https://msdn.microsoft.com/en-us/library/ms189493.aspx

ベストプラクティス

ファイルを圧縮する場合は、次の情報を考慮してください。

  • 縮小操作は、テーブルの切り捨て操作やテーブルの削除操作など、多くの未使用領域を作成する操作の後に最も効果的です。
  • ほとんどのデータベースでは、通常の日常業務に使用できる空き領域が必要です。データベースを繰り返し縮小し、データベースサイズが再び大きくなることに気付いた場合、これは通常の操作に縮小されたスペースが必要であることを示しています。これらの場合、データベースを繰り返し縮小することは無駄な操作です。
  • 縮小操作では、データベース内のインデックスの断片化状態が保持されず、一般的にある程度断片化が増加します。これは、データベースを繰り返し圧縮しないもう1つの理由です。
  • 同じデータベース内の複数のファイルを同時にではなく順次に圧縮します。システムテーブルでの競合は、ブロッキングによる遅延を引き起こす可能性があります。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.