Thêm SPARSE làm cho bảng lớn hơn nhiều


9

Tôi có một bảng nhật ký chung, khoảng 5m hàng.
Có một trường "được gõ mạnh" lưu trữ loại sự kiện và một loạt các cột "được gõ một cách thất bại" có chứa dữ liệu liên quan đến sự kiện. Đó là, ý nghĩa của các cột "gõ một cách thất bại" phụ thuộc vào loại sự kiện.

Các cột này được định nghĩa là:

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

Cột 1 và 2 trong mỗi loại được sử dụng nhiều, nhưng bắt đầu từ số 3, rất ít loại sự kiện sẽ cung cấp nhiều thông tin này. Do đó, tôi đã quyết định đánh dấu các cột 3-5 trong mỗi loại là SPARSE.

Tôi đã thực hiện một số phân tích đầu tiên và thấy rằng, thực sự, ít nhất 80% dữ liệu trong mỗi cột đó là null, và trong một số 100% dữ liệu là null. Theo bảng ngưỡng tiết kiệm 40% , SPARSEsẽ là một chiến thắng rất lớn đối với họ.

Vì vậy, tôi đã đi và áp dụng SPARSEcho các cột 3-5 trong mỗi nhóm. Bây giờ bảng của tôi mất khoảng 1,8Gb trong không gian dữ liệu như được báo cáo sp_spaceused, trong khi trước khi phát hiện ra nó là 1Gb.

Tôi đã thử dbcc cleantable, nhưng nó không có hiệu quả.
Sau đó dbcc shrinkdatabase, cũng không có tác dụng.

Bối rối, tôi gỡ bỏ SPARSEvà lặp lại dbccs. Kích thước của bảng vẫn ở mức 1,8Gb.

Đưa cái gì?


Sẽ cố gắng và sinh sản. Chỉ cần kích hoạt nó làm cho bất kỳ sự khác biệt là bảng một đống hoặc nó có một chỉ mục cụm?
Martin Smith

@MartinSmith Có chỉ số cụm rowid int not null identity(1,1) primary key clustered.
GSerg

Câu trả lời:


14

Bạn cần xây dựng lại chỉ mục được nhóm sau khi làm cho các cột thưa thớt. Các cột bị rớt vẫn tồn tại trong trang dữ liệu cho đến khi bạn làm điều này như có thể nhìn thấy bằng một truy vấn chống lại sys.system_internals_partition_columnshoặc sử dụngDBCC 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
Tuyệt vời. Chúng ta có nên coi đó là một lỗi trong tài liệu ? "Công cụ cơ sở dữ liệu SQL Server sử dụng quy trình sau để thực hiện thay đổi này: 1) Thêm một cột mới vào bảng theo kích thước và định dạng lưu trữ mới. 2) Đối với mỗi hàng trong bảng, hãy cập nhật và sao chép giá trị được lưu trữ trong cũ cột vào cột mới. 3) Xóa cột cũ khỏi lược đồ bảng. 4) Xây dựng lại bảng để lấy lại không gian được sử dụng bởi cột cũ. "
GSerg

3
@GSerg - À đúng rồi. Đồng ý có vẻ như điểm 4 không đúng. Cho rằng bạn đang làm điều này trong 12 cột thì bạn sẽ không muốn việc xây dựng lại xảy ra ngầm cho mỗi cột mặc dù có vẻ như hành vi đó là đúng nhưng không phải là tài liệu.
Martin Smith

1
@QueryKiwi - Cảm ơn. Xong
Martin Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.