Tôi có thể chèn số lượng lớn vào một bảng nén trang trống và được nén hoàn toàn không?


7

Tôi có rất nhiều bảng lớn (khoảng 10 triệu hàng rộng) cần được tải thường xuyên vào SQL Server 2016 để báo cáo chỉ đọc. Tôi muốn các bảng này càng nhỏ càng tốt trên đĩa và điều này quan trọng hơn các cải tiến hiệu suất trong việc tải hoặc truy vấn.

Đây là những gì tôi đã làm cho các bảng không yêu cầu lập chỉ mục nữa:

  1. Tạo bảng với DATA_COMPRESSION=PAGE.
  2. Sử dụng bcp để chèn số lượng lớn dữ liệu từ một tệp phẳng vào bảng mới.

Các loại cột trong các bảng là varchar (không bao giờ nhiều hơn 512, không tối đa), float, tinyint hoặc date (không phải datetime). Tất cả các cột được tạo là nullable và không có khóa chính hoặc khóa ngoài nào được xác định - chúng không quan trọng đối với truy vấn và các bảng không bao giờ được cập nhật trực tiếp. Đối chiếu mặc định trên tất cả mọi thứ là SQL_Latin1_General_CP1_CI_AS.

Khi tôi làm điều này, tôi có thể thấy sys.allocation_unitsrằng nén dữ liệu trang đã được áp dụng cho heap và tôi có thể thấy sys.partitionsrằng hệ số điền chính xác là 0 (100%). Vì các bảng nhỏ hơn nhiều so với các bảng không nén, tôi nghĩ rằng việc nén đã được thực hiện.

Tuy nhiên, nếu sau đó tôi xây dựng lại với cùng một tùy chọn DATA_COMPRESSION=PAGE, bảng được cho là đã nén sẽ nhỏ hơn khoảng 30%! Có vẻ như nó sẽ đi từ khoảng 17 hàng trên mỗi trang dữ liệu đến 25 hàng trên mỗi trang. (Tuy nhiên, chỉ một lần duy nhất. Việc xây dựng lại sau đó không làm cho nó nhỏ hơn lần xây dựng đầu tiên đã làm.)

Những câu hỏi

Vì vậy, câu hỏi của tôi là: (a) những gì đang xảy ra ở đây? và (b) có cách nào để có được kích thước nén cực nhỏ này trực tiếp khi tôi tải bảng mà không phải xây dựng lại sau khi dữ liệu được tải không?

Câu trả lời:


8

@HandyD là hoàn toàn chính xác, tôi chỉ muốn làm nổi bật một số phương pháp khác để có được nén trong khi chèn vào một đống.

Từ cùng một tài liệu

Khi heap được cấu hình để nén cấp trang, các trang chỉ nhận được nén cấp trang theo các cách sau:

  • Dữ liệu được nhập số lượng lớn với tối ưu hóa hàng loạt được kích hoạt.
  • Dữ liệu được chèn bằng cú pháp INSERT INTO ... VỚI (TABLOCK) và bảng không có chỉ mục không bao gồm.
  • Một bảng được xây dựng lại bằng cách thực hiện câu lệnh ALTER TABLE ... REBUILD với tùy chọn nén PAGE.

Theo đó, bạn có thể tận dụng các phần chèn hàng loạt được ghi lại tối thiểu hoặc sử dụng INSERT INTO ... WITH (TABLOCK) để có được PAGEnén mà không phải thực hiện xây dựng lại.


(a) chuyện gì đang xảy ra ở đây? và (b) có cách nào để có được kích thước nén cực nhỏ này trực tiếp khi tôi tải bảng mà không phải xây dựng lại sau khi dữ liệu được tải không?

Có các quy tắc để có được PAGEnén khi chèn vào một đống, thêm -h "TABLOCK"vào bcplệnh của bạn để có được nén.

ROWnén hoạt động mà không có các điều kiện tiên quyết này và là mức nén ít nhất được sử dụng trong các ví dụ dưới đây, cảm ơn @DenisRubashkin đã chỉ ra điều đó!


Kiểm tra

Ví dụ bắt đầu dữ liệu & lệnh BCP out


--Tested on SQL Server 2014 SP2

CREATE TABLE dbo.CompressedHeap_Source( Val varchar(512), 
                                 Datefield Date, 
                                 Tinyfield TinyINT,
                                 Floatfield float) 
WITH (DATA_COMPRESSION = PAGE);

INSERT INTO dbo.CompressedHeap_Source
(
Val,Datefield,Tinyfield,Floatfield)

SELECT 'Bla',cast(getdate() as date),1,1.2412
FROM master..spt_values spt1
CROSS APPLY master..spt_values spt2;

--bcp TEST.dbo.CompressedHeap_Source out E:\Data\HeapData.bcp -c -T

Các ROWnén và không nén kích thước

Kích thước dữ liệu là 132272 KBkhi thực hiện chèn tiêu chuẩn vào heap, đây là ROWnén nhưng không được PAGEnén.

Kích thước dữ liệu mà không có bất kỳ nén là ~ 176216 KBcho thử nghiệm của chúng tôi.

exec sp_spaceused 'dbo.CompressedHeap_Source'

name                    rows                    reserved    data      index_size    unused
CompressedHeap_Source   6365530                 132296 KB   132272 KB   8 KB    16 KB

XÁC NHẬN VÀO ... VỚI TABLOCK

Chèn WITH TABLOCKcho chúng ta PAGEkích thước dữ liệu nén , 69480 KB.

INSERT INTO dbo.CompressedHeap_Source2  WITH(TABLOCK)
(
Val,Datefield,Tinyfield,Floatfield)

SELECT 'Bla',cast(getdate() as date),1,1.2412
FROM master..spt_values spt1
CROSS APPLY master..spt_values spt2

SỐ LƯỢNG LỚN

Bây giờ khi chúng ta tạo một bảng heap đích cũng được pagenén và thực hiện chèn số lượng lớn with tablock:

CREATE TABLE dbo.CompressedHeap_Destination( Val varchar(512), 
                                 Datefield Date, 
                                 Tinyfield TinyINT,
                                 Floatfield float) 
WITH (DATA_COMPRESSION = PAGE);

bulk insert dbo.CompressedHeap_Destination

from 'E:\Data\HeapData.bcp'  with (TABLOCK)

Dữ liệu được pagenén và cũng tại 69480 KB:

name    rows    reserved    data    index_size  unused
CompressedHeap_Destination  6365530                 69512 KB    69480 KB    8 KB    24 KB

BCP TRONG VỚI TABLOCK

Bạn có thể nhận được kết quả tương tự như BULK INSERT WITH TABLOCKbằng cách sử dụng BCP INvới -h "TABLOCK"gợi ý. Điều này có ý nghĩa, họ làm tương tự trong nội bộ

--bcp TEST.dbo.CompressedHeap_Destination2 IN E:\Data\HeapData.bcp -c -T -h "TABLOCK"

Với kích thước kết quả là 69480 KB

BCP KHÔNG CÓ TABLOCK

Sử dụng BCP để tải dữ liệu từ cùng một tệp trong bản sao của bảng đích

Và một lệnh bcp tiêu chuẩn dẫn đến dữ liệu không được nén:

--bcp TEST.dbo.CompressedHeap_Destination2 IN E:\Data\HeapData.bcp -c -T 

Với kích thước dữ liệu tại 132272 KB(hàng nén).


2
Tôi nghĩ rằng việc xây dựng lại bảng "nén" sẽ làm giảm kích thước của nó. Có vẻ như bảng được nén ROW và phải được xây dựng lại để nén PAGE.
Denis Rubashkin

@DenisRubashkin Cảm ơn rất nhiều! Bạn đã đúng, đây không phải là nén mà thực tế là nén hàng. Xấu của tôi
Randi Vertongen

Tôi cập nhật câu trả lời, cảm ơn một lần nữa!
Randi Vertongen

Bạn đúng! Thêm -h TABLOCK vào lệnh bcp đã tạo ra sự khác biệt! Bây giờ có vẻ như quá rõ ràng rằng bạn đã chỉ ra nó, nhưng tôi đã bỏ lỡ nó hoàn toàn trước đây. (Trên thực tế, câu hỏi tiếp theo: có cách nào để nói rằng chỉ có dữ liệu được nén trong một bảng có phân bổ để nén trang không?)
Caitlin M. Shaw

2
Randi: câu trả lời hay :-). @ CaitlinM.Shaw (và Randi): Đó là một câu hỏi tuyệt vời. Vâng, có một cách để nói. Nếu bạn đăng câu hỏi đó, và sau đó đăng một liên kết đến nó trong một bình luận trả lời ở đây (vui lòng chắc chắn sử dụng @tên của tôi để tôi được thông báo), tôi sẽ đăng câu trả lời.
Solomon Rutzky

5

Theo bài viết trên Docs về nén:

Các trang mới được phân bổ trong một đống như một phần của các hoạt động DML không sử dụng nén PAGE cho đến khi heap được xây dựng lại. Xây dựng lại heap bằng cách loại bỏ và áp dụng lại nén, hoặc bằng cách tạo và xóa một chỉ mục được nhóm.

Điều này dường như phù hợp với những gì bạn đang thấy. Có vẻ như bạn không thực sự bị nén trên bàn cho đến khi bạn xây dựng lại nó. Bạn có thể thử tải dữ liệu trên một bảng không nén và xem liệu bạn vẫn còn trung bình 17 hàng trên mỗi trang hay nếu điều này giảm. Nếu nó vẫn giữ nguyên, thì bạn không bị nén và việc xây dựng lại là cần thiết.

Bạn cũng có thể thêm một chỉ mục được nhóm vào bảng của mình và điều đó sẽ ngăn bảng của bạn không bị nén / nén thấp sau khi tải số lượng lớn dữ liệu của bạn.

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.