web-dev-qa-db-ja.com

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

この質問はここでさまざまな形式で行われますが、質問は次のようになります。

データベースを縮小するのは危険だと知っています。この場合、私は非常に多くのデータを削除したので、それを二度と使用しません。

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

いくつかの初期警告:

  1. 運用データベースまたはデータファイルをever縮小することは、一般的にワーストプラクティスとして知られています(ログファイルは この質問)として別の問題です =について話します)。 このようなブログ投稿 でデータベースを縮小しないように人々にアドバイスします。ここでは、「適切なサイズ設定」と適切な計画について説明します。私はそこにいるだけではありません( Paul RandalBrent Ozar 、いくつかのリンクを提供するだけです)。データファイルまたはデータベースフラグメントインデックスの縮小は、リソースに時間がかかり、面倒であり、システムの負荷になる可能性があり、一般に
  2. この場合、私たちは皆、リスクがあることを知っており、それに対処する準備ができていますが、知っているしたがって、この特定のタイプの場合-縮小は、選択肢の1つとして非常に理にかなっています。

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

2つの主要なアプローチがここで考慮されます:

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

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

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

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

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

amforce でデータベースを圧縮する場合これが私の環境である場合は、私はディスクを独り占めし、将来の/予期しない成長に備えたいと思っているので、データファイルにかなりの量のホワイトスペースがあります。ですから、スペースの大部分を削除しただけでスペースを返却しても大丈夫ですが、「しかし、二度と成長しない」と言っている人を信用せず、 some を残しますスペース。おそらく私が使用するルート( sigh )は、ダウンタイムウィンドウが小さく、空のDBを作成してデータを移行する複雑さを望まない場合の縮小アプローチです。それ。だから私はそれを何回か段階的に縮小し(開発でのテストと希望のサイズに基づいて必要な回数に基づいて、徐々に小さいファイルサイズを選択することに基づいて)、インデックスを再構築しました。そして、私は自分のデータベースを縮小したとは誰にも言いません;-)

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

とにかく定期的に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。*スキーマのテーブルのみに関心があると想定しています。

4
Csaba Toth

データベースの縮小に関するすべての警告を聞いたことがあり、それらはすべて真実です。それはあなたのインデックスを断片化します、そして、一般的に、あなたのデータベースを汚します、そして、生産システムで行われるべきではありません。

しかし、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
2
user1207758

以下のこの引用はMicrosoftから直接のものであり(バージョン2008-2016に適用)、DBCC SHRINKFILEコマンド。

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

ベストプラクティス

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

  • 縮小操作は、テーブルの切り捨て操作やテーブルの削除操作など、多くの未使用領域を作成する操作の後に最も効果的です。
  • ほとんどのデータベースでは、日常の日常業務で使用できる空き容量が必要です。データベースを繰り返し縮小し、データベースのサイズが再び大きくなることに気づいた場合、これは、縮小されたスペースが通常の操作に必要であることを示しています。これらの場合、データベースを繰り返し縮小することは無駄な操作です。
  • 圧縮操作では、データベース内のインデックスの断片化の状態は保持されず、通常は断片化がある程度増加します。これは、データベースを繰り返し縮小しない別の理由です。
  • 同じデータベース内の複数のファイルを同時にではなく順次圧縮します。システムテーブルの競合により、ブロッキングが原因で遅延が発生する可能性があります。
1
g2server