나는 다른 답변 (환영합니다, Niko!)으로 Niko에 가입하는 것을 거부 할 수 없었습니다. 일반적으로, 나는 SQL 2012 의 배치 모드 제한 (Niko가 자신의 블로그에 링크하지 않는 경우 :))이 주요 관심사 일 수 있다는 Niko에 동의합니다 . 그러나 그와 함께 살 수 있고 신중하게 조사하기 위해 테이블에 대해 작성하는 모든 쿼리를 완전히 제어 할 수 있다면 columnstore는 SQL 2012에서 효과적 일 수 있습니다.
신원 열에 대한 귀하의 특정 질문에 대해서는 신원 열이 매우 잘 압축되어 초기 테스트에서 열 저장소 색인에 포함시키는 것이 좋습니다. (identity 열이 b-tree의 클러스터 된 인덱스이기도 한 경우 비 클러스터형 columnstore 인덱스에 자동으로 포함됩니다 .)
참고로, ~ 10MM 행의 식별 열 데이터에서 관찰 한 크기는 다음과 같습니다. 최적의 세그먼트 제거를 위해로드 된 열 저장소는 26MB ( PAGE
행 저장소 테이블 압축의 경우 113MB) 로 압축되며 무작위로 정렬 된 b- 트리에 빌드 된 열 저장소도 40MB에 불과합니다. 따라서 이것은 최고의 b-tree 압축보다 SQL이 제공해야 할 최적의 세그먼트 제거를 위해 데이터를 정렬하지 않아도 (b-tree를 만든 다음 수행 할 때) 압축에 큰 이점을 보여줍니다. MAXDOP
1)로 열 상점을 구축하십시오 .
다음은 내가 놀고 싶을 때 사용한 전체 스크립트입니다.
-- 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