SPARSE eklenmiş tablo çok daha büyük


9

Genel bir günlük tablo, yaklaşık 5m satır var.
Olay türünü depolayan "güçlü bir şekilde yazılan" alan ve olayla ilgili verileri içeren bir grup "yavaş yazılan" sütun var. Yani, bu "yavaş yazılan" sütunların anlamı olayın türüne bağlıdır.

Bu sütunlar şu şekilde tanımlanır:

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

Her türdeki Sütun 1 ve 2 yoğun bir şekilde kullanılır, ancak 3 numaradan başlayarak çok az sayıda etkinlik türü bu kadar bilgi sağlar. Bu nedenle her tipte 3-5 arasındaki sütunları işaretlemek istedim SPARSE.

Önce bazı analizler yaptım ve gerçekten de, bu sütunların her birindeki verilerin en az% 80'inin ve verilerin null% 100'ünde olduğunu gördüm null. Göre % 40 tasarruf eşik masaya , SPARSEüzerlerinde büyük bir kazanç olacaktır.

Bu yüzden gittim ve SPARSEher grupta 3-5 sütunlara başvurdum . Şimdi benim masam tarafından bildirildiği gibi veri alanı yaklaşık 1.8Gb sp_spaceusedalırken, yedeklemeden önce 1Gb oldu.

Denedim dbcc cleantableama hiçbir etkisi olmadı.
Sonra dbcc shrinkdatabaseda etkisi yok.

Şaşkın, kaldırdım SPARSEve tekrarladı dbcc. Tablonun boyutu 1.8Gb'de kaldı.

Ne oluyor?


Yeniden üretmeye çalışacak. Sadece herhangi bir fark yapar tablo bir yığın mı yoksa kümelenmiş bir dizin var mı?
Martin Smith

@MartinSmith Kümelenmiş bir dizin var rowid int not null identity(1,1) primary key clustered.
GSerg

Yanıtlar:


14

Sütunları seyrek yaptıktan sonra kümelenmiş dizini yeniden oluşturmanız gerekir. Bırakılan sütunlar, siz bunu yapan sys.system_internals_partition_columnsveya kullanan bir sorgu ile görülebilinceye kadar veri sayfasında bulunmaya devam ederDBCC 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
Muhteşem. Belgelerde bir hata olarak kabul etmeli miyiz ? "SQL Server Veritabanı Altyapısı bu değişikliği gerçekleştirmek için aşağıdaki yordamı kullanır: 1) Yeni depolama boyutu ve biçiminde tabloya yeni bir sütun ekler. 2) Tablodaki her satır için, eski depolanan değeri güncelleştirir ve kopyalar 3) Eski sütunu tablo şemasından kaldırır.4) Eski sütunun kullandığı alanı geri kazanmak için tabloyu yeniden oluşturur. "
GSerg

3
@GSerg - Ah doğru. Kabul ediyorum o zaman nokta 4 doğru değil. Bunu 12 sütun için yaptığınız göz önüne alındığında, yeniden oluşturma her sütun için örtük olarak gerçekleşmesini istemezsiniz, ancak davranış doğru görünüyor ancak belgeler değil.
Martin Smith

1
@SQLKiwi - Teşekkürler. Tamamlandı
Martin Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.