Tôi không thể cưỡng lại việc tham gia Niko với một câu trả lời khác (chào mừng, Niko!). Nói chung, tôi đồng ý với Niko rằng các giới hạn chế độ hàng loạt trong SQL 2012 (nếu Niko sẽ không liên kết với blog của riêng anh ấy, tôi sẽ :)) có thể là một mối quan tâm lớn. Nhưng nếu bạn có thể sống với những điều đó và có toàn quyền kiểm soát mọi truy vấn bạn đang viết trên bảng để kiểm tra cẩn thận thì cột đó có thể hoạt động cho bạn trong SQL 2012.
Theo như các câu hỏi cụ thể của bạn về cột định danh, tôi thấy rằng cột nhận dạng nén rất tốt và rất khuyến khích đưa nó vào chỉ mục của cửa hàng cột trong bất kỳ thử nghiệm ban đầu nào của bạn. (Lưu ý rằng nếu cột danh tính cũng là chỉ mục được nhóm của cây b của bạn, thì nó sẽ tự động được bao gồm trong chỉ mục của cửa hàng cột không được phân cụm .)
Để tham khảo, đây là các kích thước tôi quan sát được cho ~ 10MM hàng dữ liệu cột nhận dạng. Kho lưu trữ cột được tải để loại bỏ phân đoạn tối ưu nén thành 26MB (so với 113 MB để PAGE
nén bảng lưu trữ hàng hóa) và thậm chí kho lưu trữ cột được xây dựng trên cây b được đặt hàng ngẫu nhiên chỉ có 40 MB. Vì vậy, điều này cho thấy lợi ích nén rất lớn, thậm chí qua SQL nén cây b tốt nhất phải cung cấp và ngay cả khi bạn không muốn căn chỉnh dữ liệu của mình để loại bỏ phân đoạn tối ưu (trước tiên bạn sẽ làm bằng cách tạo cây b và sau đó xây dựng cửa hàng cột của bạn với MAXDOP
1).
Dưới đây là toàn bộ kịch bản tôi đã sử dụng trong trường hợp bạn muốn chơi xung quanh:
-- Confirm SQL version
SELECT @@version
--Microsoft SQL Server 2012 - 11.0.5613.0 (X64)
-- May 4 2015 19:05:02
-- Copyright (c) Microsoft Corporation
-- Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 <X64> (Build 9600: )
-- Create a columnstore table with identity column that is the primary key
-- This will yield 10 columnstore segments @ 1048576 rows each
SELECT i = IDENTITY(int, 1, 1), ROW_NUMBER() OVER (ORDER BY randGuid) as randCol
INTO #testIdentityCompression_sortedColumnstore
FROM (
SELECT TOP 10485760 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS randI, NEWID() AS randGuid
FROM master..spt_values v1
CROSS JOIN master..spt_values v2
CROSS JOIN master..spt_values v3
) r
ORDER BY r.randI
GO
ALTER TABLE #testIdentityCompression_sortedColumnstore
ADD PRIMARY KEY (i)
GO
-- Load using a pre-ordered b-tree and one thread for optimal segment elimination
-- See http://www.nikoport.com/2014/04/16/clustered-columnstore-indexes-part-29-data-loading-for-better-segment-elimination/
CREATE NONCLUSTERED COLUMNSTORE INDEX cs_#testIdentityCompression_sortedColumnstore ON #testIdentityCompression_sortedColumnstore (i) WITH (MAXDOP = 1)
GO
-- Create another table with the same data, but randomly ordered
SELECT *
INTO #testIdentityCompression_randomOrderColumnstore
FROM #testIdentityCompression_sortedColumnstore
GO
ALTER TABLE #testIdentityCompression_randomOrderColumnstore
ADD UNIQUE CLUSTERED (randCol)
GO
CREATE NONCLUSTERED COLUMNSTORE INDEX cs_#testIdentityCompression_randomOrderColumnstore ON #testIdentityCompression_randomOrderColumnstore (i) WITH (MAXDOP = 1)
GO
-- Create a b-tree with the identity column data and no compression
-- Note that we copy over only the identity column since we'll be looking at the total size of the b-tree index
-- If anything, this gives an unfair "advantage" to the rowstore-page-compressed version since more
-- rows fit on a page and page compression rates should be better without the "randCol" column.
SELECT i
INTO #testIdentityCompression_uncompressedRowstore
FROM #testIdentityCompression_sortedColumnstore
GO
ALTER TABLE #testIdentityCompression_uncompressedRowstore
ADD PRIMARY KEY (i)
GO
-- Create a b-tree with the identity column and page compression
SELECT i
INTO #testIdentityCompression_compressedRowstore
FROM #testIdentityCompression_sortedColumnstore
GO
ALTER TABLE #testIdentityCompression_compressedRowstore
ADD PRIMARY KEY (i)
WITH (DATA_COMPRESSION = PAGE)
GO
-- Compare all the sizes!
SELECT OBJECT_NAME(p.object_id, 2) AS tableName, COUNT(*) AS num_segments, SUM(on_disk_size / (1024.*1024.)) as size_mb
FROM tempdb.sys.partitions p
JOIN tempdb.sys.column_store_segments s
ON s.partition_id = p.partition_id
AND s.column_id = 1
WHERE p.object_id IN (OBJECT_ID('tempdb..#testIdentityCompression_sortedColumnstore'),OBJECT_ID('tempdb..#testIdentityCompression_randomOrderColumnstore'))
GROUP BY p.object_id
UNION ALL
SELECT OBJECT_NAME(p.object_id, 2) AS tableName
, NULL AS num_segments
, (a.total_pages*8.0) / (1024.0) as size_mb
FROM tempdb.sys.partitions p
JOIN tempdb.sys.allocation_units a
ON a.container_id = p.partition_id
WHERE p.object_id IN (OBJECT_ID('tempdb..#testIdentityCompression_compressedRowstore'),OBJECT_ID('tempdb..#testIdentityCompression_uncompressedRowstore'))
ORDER BY 3 ASC
GO