次のスクリプトを使用して、Azure上のSQL Serverであるデータベースからデータを収集します。
-- Script to run against database to gather metrics
CREATE TABLE #SpaceUsed (name sysname,rows bigint,reserved sysname,data sysname,index_size sysname,unused sysname)
DECLARE @Counter int
DECLARE @Max int
DECLARE @Table sysname
SELECT name, IDENTITY(int,1,1) ROWID
INTO #TableCollection
FROM sysobjects
WHERE xtype = 'U'
ORDER BY lower(name)
SET @Counter = 1
SET @Max = (SELECT Max(ROWID) FROM #TableCollection)
WHILE (@Counter <= @Max)
BEGIN
SET @Table = (SELECT name FROM #TableCollection WHERE ROWID = @Counter)
INSERT INTO #SpaceUsed
EXECUTE sp_spaceused @Table
SET @Counter = @Counter + 1
END
SELECT * FROM #SpaceUsed
DROP TABLE #TableCollection
DROP TABLE #SpaceUsed
私のテーブルの1つは53 GB in size
、38 GB in data
、14 GB in unused
。インデックスは11 MB in size
。それを取り戻すにはどうすればよいですか14 GB that is unused
?これはAzureにあるため、余分なスペースにはコストがかかります。
さまざまな記事を読んだ後、次のことを試して、テーブルのサイズを小さくしました。
DBCC DBREINDEX ('myTableName', ' ')
DBCC SHRINKDATABASE (myDatabaseName, 10);
ただし、これらが完了しても、テーブルのサイズは変更されません。未使用のスペースを再利用するために、テーブルとデータベースのサイズを縮小するにはどうすればよいですか?
更新:テーブルには24列があり、9つのフィールドがvarchar(> 4000)またはvarchar(MAX)です。別の8列は一意の識別子タイプです。
ヒープでもクラスタ化インデックスでも、再構築することでテーブル内のスペースを再利用できることがわかります。
ALTER INDEX ALL ON dbo.myTableName REBUILD;
テーブル内のスペースの再利用とデータベースの縮小は、2つのまったく別のものであることに注意してください。データベースを縮小することは例外的なことです。ディスク容量を解放するためだけにデータベースを縮小しないでください。ほとんどの場合、データベースはとにかく拡大してその容量を再び使用する必要があるためです。
テーブルの分散方法を決定するために、sp_spaceused
は、すべてのデータを含む単一の項目を提供するだけなので、ほとんど役に立ちません。まず、テーブルが分割されているかどうかを確認します。これは次のようにしてすばやく確認できます。
SELECT COUNT(*)
FROM sys.partitions
WHERE partition_number > 1
AND object_id = OBJECT_ID(N'dbo.myTableName');
次に、7つのインデックス間でデータがどのように配置されるかを確認します。これらの1つが必要以上に大きい場合は、LOBスペースが不足している可能性があるため、ドロップ/再作成(たとえば、XML列をINCLUDE
リストから削除する可能性がある)を試すことができます。削除した行またはNULL
に設定した行は、再構築した後でも完全に回復されません。
;WITH x AS
(
SELECT i.name, type = pa.allocation_unit_type_desc, kb = COUNT(*) * 8
FROM sys.indexes AS i
CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), i.object_id, i.index_id,
NULL, 'LIMITED') AS pa
WHERE i.[object_id] = OBJECT_ID(N'dbo.myTableName')
GROUP BY GROUPING SETS((), (i.name, pa.allocation_unit_type_desc))
)
SELECT name, type, kb,
[%] = CONVERT(decimal(5,2), kb*100.0/(SELECT kb FROM x WHERE name IS NULL))
FROM x
WHERE name IS NOT NULL
ORDER BY name, type;
ベーステーブルの個々の行のサイズを確認する場合は、次のようにします。
SELECT TOP (100) key, rowsize = DATALENGTH(col1) + DATALENGTH(col2) + ...
FROM dbo.myTableName
ORDER BY rowsize DESC;
かなり大きいデータがある場合は、そのデータが必要であることを確認することをお勧めします(そうでない場合は、サイズに影響している可能性があるため、NULL
に設定してください)。
テーブルとインデックスのFILL FACTORを確認して、ページの多くのスペースを明示的に予約していないことを確認してください。次のコマンドを実行します。
SELECT t.name as TableName
,COALESCE(i.name,'<no index>') as IndexName
,i.type_desc
,i.Fill_Factor
FROM sys.tables t INNER JOIN sys.indexes i ON t.object_id = i.object_id
;
フィルファクターは、SQLエンジンに、テーブルまたはインデックスを作成するときに、作成する各ページに残す空き容量を伝えます。ページにデータが入力されると、SQLはページがいっぱいになるまで情報をページに追加し、新しいページを作成して、適切な量(通常は約半分)のデータを新しいページに移動します。
インデックスの1つがFILL FACTORが低い場合(75未満、ただし0を超える場合(実際には0は基本的に100%にフィルされることを意味します))、データベース内の未使用スペースが大量にあることを説明している可能性があります。
インデックスのFILL FACTORを(たとえば)90%に変更したい場合は、ALTER INDEX
Aaron Bertrandの回答からのコマンド:
ALTER INDEX ALL ON dbo.myTableName REBUILD WITH FILLFACTOR = 90;