SPARSEを追加すると、テーブルがはるかに大きくなります


9

約5m行の汎用ログテーブルがあります。
イベントタイプを格納する「厳密に型指定された」フィールドと、イベントに関連するデータを含む一連の「緩やかに型指定された」列があります。つまり、これらの「緩やかに型付けされた」列の意味は、イベントの型によって異なります。

これらの列は次のように定義されます。

USER_CHAR1 nvarchar(150) null,
USER_CHAR2 nvarchar(150) null,
USER_CHAR3 nvarchar(150) null,
USER_CHAR4 nvarchar(150) null,
USER_CHAR5 nvarchar(150) null,

USER_INTEGER1 int null,
USER_INTEGER2 int null,
USER_INTEGER3 int null,
USER_INTEGER4 int null,
USER_INTEGER5 int null,

USER_FLAG1 bit null,
USER_FLAG2 bit null,
USER_FLAG3 bit null,
USER_FLAG4 bit null,
USER_FLAG5 bit null,

USER_FLOAT1 float null,
USER_FLOAT2 float null,
USER_FLOAT3 float null,
USER_FLOAT4 float null,
USER_FLOAT5 float null

各タイプの列1と2は頻繁に使用されますが、番号3から始めて、非常に少数のイベントタイプがこれだけの情報を提供します。したがって、各タイプの列3〜5をとマークすることを検討しましたSPARSE

最初にいくつかの分析を行ったところ、実際、これらの各列のデータの少なくとも80%はnullであり、一部の100%のデータはであることがわかりましたnull40%の節約のしきい値の表によると、SPARSEそれらに大きな勝利をもたらすでしょう。

それで、私は行ってSPARSE、各グループの列3〜5に適用しました。現在、私のテーブルはsp_spaceused、によって報告されたようにデータスペースで約1.8Gbを使用していますが、スパースする前は1Gbでした。

試しましたdbcc cleantableが効果がありませんでした。
その後dbcc shrinkdatabase、影響もありません。

困惑し、私SPARSEdbccs を削除して繰り返しました。テーブルのサイズは1.8Gbのままでした。

何ができますか?


再現してみます。テーブルがヒープであるか、それともクラスター化インデックスがあるかによって、違いが生じる場合がありますか?
マーティン・スミス

@MartinSmithにはクラスター化インデックスがありますrowid int not null identity(1,1) primary key clustered
GSerg

回答:


14

列をスパースにした後、クラスター化インデックスを再構築する必要があります。あなたがこれを行うまでの列がまだに対する照会すると分かるように、データ・ページ内に存在するドロップsys.system_internals_partition_columnsまたは使用DBCC PAGE

SET NOCOUNT ON;
CREATE TABLE Thing 
(
ThingId int IDENTITY CONSTRAINT PK PRIMARY KEY,
USER_CHAR1 nvarchar(150) null,
USER_CHAR2 nvarchar(150) null,
USER_CHAR3 nvarchar(150) null,
USER_CHAR4 nvarchar(150) null,
USER_CHAR5 nvarchar(150) null
)
INSERT INTO Thing
SELECT REPLICATE('A',150),
       CASE WHEN number % 5 = 1 THEN REPLICATE('A',150) END,
       CASE WHEN number % 5 = 2 THEN REPLICATE('A',150) END,
       CASE WHEN number % 5 = 3 THEN REPLICATE('A',150) END,              
       CASE WHEN number % 5 = 4 THEN REPLICATE('A',150) END
FROM master..spt_values   

EXEC sp_spaceused 'Thing'

ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR2 ADD SPARSE
ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR3 ADD SPARSE
ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR4 ADD SPARSE
ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR5 ADD SPARSE

DECLARE @DynSQL NVARCHAR(MAX);

SELECT @DynSQL =  'DBCC TRACEON (3604);
                   DBCC PAGE(0, ' + LEFT(file_id,10) + ', ' + LEFT(page_id,10) + ', 3); 
                   DBCC TRACEOFF(3604); ' 
FROM Thing
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%)
WHERE ThingId=76

EXEC(@DynSQL)    

SELECT pc.*
FROM sys.system_internals_partition_columns pc
JOIN sys.partitions p on p.partition_id=pc.partition_id
WHERE p.object_id = object_id('Thing')
AND pc.is_dropped=1

 EXEC sp_spaceused 'Thing'

ALTER INDEX PK ON Thing REBUILD;    

SELECT @DynSQL =  'DBCC TRACEON (3604);
                   DBCC PAGE(0, ' + LEFT(file_id,10) + ', ' + LEFT(page_id,10) + ', 3); 
                   DBCC TRACEOFF(3604); ' 
FROM Thing
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%)
WHERE ThingId=76

EXEC(@DynSQL)    

SELECT pc.*
FROM sys.system_internals_partition_columns pc
JOIN sys.partitions p on p.partition_id=pc.partition_id
WHERE p.object_id = object_id('Thing')
AND pc.is_dropped=1

EXEC sp_spaceused 'Thing'

DROP TABLE Thing 

1
驚くばかり。ドキュメントのバグと見なす必要がありますか?「SQL Serverデータベースエンジンは、次の手順を使用してこの変更を行います。1)テーブルに新しいストレージサイズとフォーマットで新しい列を追加します。2)テーブルの各行について、古い列に保存された値を更新してコピーします列を新しい列に
変換

3
@GSerg-ああそうだ。その点では、ポイント4は正しくないと思われます。これを12列で実行しているとすると、各列で暗黙的に再構築が発生するのは望ましくありませんが、動作は正しいようですが、ドキュメントではありません。
マーティン・スミス

1
@SQLKiwi-ありがとう。完了
Martin Smith
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.