約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%のデータはnull
であることがわかりました。 40%節約のしきい値の表 によると、SPARSE
は彼らに大きな勝利をもたらすでしょう。
そこで、各グループの列3〜5にSPARSE
を適用しました。これで、私のテーブルはsp_spaceused
によって報告されたように約1.8Gbのデータ領域を使用しますが、スパーリングする前は1Gbでした。
dbcc cleantable
を試しましたが、効果がありませんでした。
その後dbcc shrinkdatabase
、影響もありません。
困惑して、私はSPARSE
を削除し、dbcc
sを繰り返しました。テーブルのサイズは1.8Gbのままでした。
何ができますか?
列をスパースにした後、クラスター化インデックスを再構築する必要があります。削除された列は、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