未使用領域のSQL Serverテーブルの解放


11

SQL Server 2012 Expressに未使用のスペースが多いテーブルがあります。

データベースのスペースを解放する必要があります。

| NAME | ROWS | 予約済み| データ| INDEX_SIZE | 未使用|
| ------------- | -------- | -------------- | ----------- --- | ------------ | -------------- |
| MyTableName | 158890 | 8928296 KB | 5760944 KB | 2248 KB | 3165104 KB |

SQLで3165104KBをリリースするにはどうすればよいですか?

私はすでに試しました:

Alter table MyTableName Rebuild
DBCC CLEANTABLE (MyDbName,"MyTableName ", 0)
ALTER INDEX ALL ON MyTableName REORGANIZE ; 
ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF) 

ここにテーブルがあります:

CREATE TABLE [dbo].[MyTableName](
    [ImageID] [int] IDENTITY(1,1) NOT NULL,
    [DateScan] [datetime] NULL,
    [ScanImage] [image] NULL,
 CONSTRAINT [PK_Image] PRIMARY KEY CLUSTERED 
(
    [ImageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

私たちが行った唯一のことはScanImage、すべての行ではるかに小さいイメージに置き換えられることです(これは、そこに未使用のスペースがどれだけあるかです)。

回答:


10

私たちが行った唯一のことはScanImage、すべての行ではるかに小さい画像に置き換えられることです(これは、そこに非常に多くの未使用のスペースがあることです)

いくつかの実験を行うことから、最もスペース効率の良い方法は、アロケーションユニットを削除して再投入することです(これを行うメンテナンスウィンドウがある場合)。

問題のテーブル構造で私にとって最良のスペース削減を達成したコード例は次のとおりです。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

BEGIN TRAN

SELECT [ImageID],
       [ScanImage]
INTO   #Temp
FROM   [dbo].[MyTableName]

ALTER TABLE [dbo].[MyTableName]
  DROP COLUMN [ScanImage]

/*Allocation unit not removed until after this*/
ALTER INDEX PK_Image ON MyTableName REBUILD

ALTER TABLE [dbo].[MyTableName]
  ADD [ScanImage] IMAGE NULL

UPDATE [dbo].[MyTableName]
SET    [ScanImage] = T.[ScanImage]
FROM   [dbo].[MyTableName] M
       JOIN #Temp T
         ON M.ImageID = T.[ImageID]

DROP TABLE #Temp

COMMIT 

すべてがトランザクション内にあるため、マシンがクラッシュした場合はロールバックされます。おそらくいくつかのエラー処理または少なくともで行うことができますSET XACT_ABORT ONSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;コピー中またはコピー後に同時変更が発生して失われるのを防ぐために使用していました。

imageすべての行のサイズを減らした後に予約されたLOBページの数は、次のとおりです。

+ ------------------------------------------------- -+ --------------------- + ------------------------- +
| イベント| lob_used_pa​​ge_count | lob_reserved_pa​​ge_count |
+ ------------------------------------------------- -+ --------------------- + ------------------------- +
| それぞれ100,000バイトのデータを含む10,000行を挿入| 135005 | 135017 |
| すべての行を10,000バイトの画像データに更新| 31251 | 135012 |
| 再編成| 23687 | 25629 |
| 画像データをドロップして再度追加する| 13485 | 13489 |
+ ------------------------------------------------- -+ --------------------- + ------------------------- +

1
または、テーブルが大きい場合は、データをBCPアウトしてから、BULK INSERTをバックして-メンテナンスウィンドウ。
Kin Shah

6

試して

ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF)

これによりクラスター化インデックスが再作成されるため、操作を完了するにはデータベースに追加のスペースが必要になります。ディスクがいっぱいで余分なスペースがない場合は、新しいデータファイルを(別のディスク上の)データベースに追加して、テーブルをそのデータベースに移動できます。

また、クラスター化インデックスが100%未満のFILLFACTORで定義されている可能性もあります。FILL FACTORをたとえば66%に設定すると、各データページの1/3が将来の使用に備えて空になります。これが問題である場合は、使用して曲線因子を変更できますALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

最近、可変長フィールドをテーブルから削除した場合は、 DBCC CLEANTABLE( Databasename, "MyTableName")

Books online(BOL)には、http://technet.microsoft.com/en-us/library/ms188388%28v=sql.100%29.aspxにインデックスの再構築に関する優れた記事があります。


2

DBリカバリモードがであることを確認してくださいSIMPLE

列をに変更しますVARBINARY(MAX)

次に、データを完全に新しいテーブルにコピーしてみます。

を使用して新しいテーブルサイズを確認しsp_spaceused "tablename"ます。テーブルの未使用スペースに満足している場合は、テーブル名を指定せずに同じコマンドを使用してデータベースの未使用スペースを確認します。そのスペースはまだデータベースファイル内にあり、OSには解放されません。

元のテーブルを削除して新しいテーブルの名前を変更するか、同じことをもう一度行って、名前の変更操作が信頼できない場合は、元のテーブル名を使用します(完全に信頼しているわけではありません)。

これが機能する場合、最後のステップは簡単です。ファイルを圧縮して未使用のスペースを解放する方法を知っています。

外部キーがある場合は、それらの定義を記録して削除し、前述のタスクを実行して、後で外部キーを再作成します。もちろんこれには時間がかかりますが、この操作はオフタイムに行う必要があります。このタスク全体をスクリプトで行うこともでき、夜通し実行できます。


1

新しいデータベースを作成してデータをコピーするだけです。インポート/エクスポートウィザードを使用できるはずです。(明らかに、バックアップと復元で問題が解決されません。)データのインポート結果を確認してください。問題がなければ、元のデータベースの名前を変更してから、新しいデータベースの名前を使用したい名前に変更します。(私は常にオリジナルを削除する前に少し待って、オンラインでダブルチェックをしています。)

価値のあるものとして、次の手順で、データベースが大きすぎない場合は、データベースからBLOBスペースを回収しました。(ただし、SQL Server Expressを使用しているため、これを試す余地がない場合があります。)

  1. ファイルグループに新しいファイルを追加します。
  2. を実行しますDBCC SHRINKFILE(file, EMPTYFILE)。MDFを縮小しているため、システムメタデータを移動できないため、最終的には失敗します。ただし、空のblob割り当ては移動されません。
  3. を実行しますDBCC SHRINKFILE(newfile,EMPTYFILE)。これにより、余分なスペースを差し引いてデータが戻されます。
  4. ファイルグループから新しいファイル(現在は空)を削除します。

これにより、ブロブの膨張がなくなります。この手法は主に、アップグレードスクリプトをテストするためのほとんど空のデータベースを作成するために使用したことを述べておきます。


-1

クラスタ化インデックスを再編成します-ノードにデータがあるため、断片化されている可能性があります。


私は実行してみました:ALTER INDEX ALL ON [MyTableName] REORGANIZE;
DermFrench 2013年

3
再構築;)再編成しない。
TomTom 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.