คอลัมน์รหัสประจำตัวในดัชนี columnstore


9

ฉันมีตาราง IMO ที่มีขนาดใหญ่มาก (~ 137 ล้านแถว) ที่มีข้อมูลซ้ำจำนวนมากNULLคอลัมน์จำนวนมากและเช่นนั้น

ฉันกำลังพิจารณาการสำรวจนี้โดยใช้ตารางที่มีCOLUMNSTORE INDEXและฉันมีIDENTITYคอลัมน์ในตารางเดิมซึ่งเป็นคอลัมน์เดียวของฉันที่ทุกแถวไม่ซ้ำกัน

ฉันควรปล่อยคอลัมน์นี้ออกหรือรวมไว้หรือไม่ ฉันได้อ่านแล้วว่าคุณต้องการรวมแถวทั้งหมดของตารางลงในCOLUMNSTORE INDEXแต่ฉันได้อ่านด้วยว่าผู้สมัครที่ดีที่สุดคือคอลัมน์ที่มีแถวที่ไม่ซ้ำจำนวนมาก

นี่เป็นเพียงผู้สมัครที่ไม่ดีสำหรับCOLUMNSTORE INDEX?

ฉันใช้ SQL Server 2012 ดังนั้นจึงเป็นคอลัมน์ที่ไม่ใช่คลัสเตอร์ ฉันแค่สำรวจวิธีที่เป็นไปได้ที่ดีกว่าในการจัดเก็บข้อมูลนี้ การปรับปรุงไม่มีอยู่แม้ว่าจะมีการเพิ่มแถวใหม่เป็นระยะ ๆ ผ่านกระบวนการ ELT ดังนั้นฉันคาดว่าจะมีงานบางอย่างเกิดขึ้นที่นั่น ผู้ใช้บางคนขุดข้อมูลนี้และสร้างรายงานจำนวนมากสแกนแถวจำนวนมากนำเซิร์ฟเวอร์ไปสู่การรวบรวมข้อมูลในบางครั้งซึ่งบังคับให้เราถ่ายสำเนาทุกวันไปยังเซิร์ฟเวอร์รอง


1
คอลัมน์ข้อมูลประจำตัวในตารางเดิมเป็นดัชนีคลัสเตอร์ของคุณหรือไม่ ถ้าเป็นเช่นนั้น SQL Server จะรวมคอลัมน์นั้นโดยอัตโนมัติในดัชนีใด ๆ ที่ไม่ใช่คลัสเตอร์คลัสเตอร์ดัชนีแม้ว่าคุณจะไม่ได้ขออย่างชัดเจน สิ่งนี้ค่อนข้างคล้ายกับวิธีที่คอลัมน์ดัชนีคลัสเตอร์จะรวมอยู่ในดัชนี b-tree ที่ไม่ได้ทำคลัสเตอร์ แต่ข้อมูลจะถูกเก็บไว้เป็นกลุ่มคอลัมน์ที่บีบอัดจริงในกรณีนี้ ดูdba.stackexchange.com/questions/103722/…สำหรับข้อมูลเพิ่มเติม
Geoff Patterson

137 million rowsใหญ่ แต่จัดการได้ คุณดูที่การแบ่งตารางและวางลงในกลุ่มไฟล์อื่นหรือไม่? ดัชนี Columnsstore ใน sql 2012 ไม่สามารถเขียนได้ดังนั้นคุณจะพบปัญหา - คุณต้องวางและสร้างใหม่ ฉันไม่ได้บอกว่าร้านค้าคอลัมน์จะไม่ดี แต่ควรสำรวจตัวเลือกอื่น ๆ ด้วยเช่นกัน
Kin Shah

คำตอบ:


11

คอลัมน์ข้อมูลประจำตัวจะไม่ถูกบีบอัดอย่างแท้จริงในดัชนี Columnstore ใน SQL Server 2012 หรือใน SQL Server 2014 ทั้งหมดจะขึ้นอยู่กับปริมาณงานที่คุณกำลังประสบอยู่อย่างแท้จริง หากปริมาณงานของคุณจะมีคอลัมน์ข้อมูลประจำตัวคุณก็สามารถใช้ประโยชน์จากการกำจัดกลุ่มได้อย่างสวยงาม

จากมุมมองการบีบอัด - Columnstore จะให้การบีบอัดที่ดีกว่าหน้าเว็บทั่วไป เป็นปกติ กรุณาทดสอบก่อนที่จะผลิต

ปัญหาที่ใหญ่ที่สุดของคุณใน SQL Server 2012 จะเป็นการใช้งานแบทช์ที่อ่อนมากและไม่มีอะไรที่คุณสามารถทำได้


7
ยินดีต้อนรับ Niko !!!
Aaron Bertrand

3

ฉันไม่สามารถต้านทานการเข้าร่วม Niko ด้วยคำตอบอื่น (ยินดีต้อนรับ Niko!) โดยทั่วไปฉันเห็นด้วยกับ Niko ว่าข้อ จำกัด โหมดแบทช์ใน SQL 2012 (หาก Niko จะไม่เชื่อมโยงไปยังบล็อกของเขาเองฉันจะ :)) อาจเป็นปัญหาที่สำคัญ แต่ถ้าคุณสามารถใช้ชีวิตอยู่กับสิ่งเหล่านั้นและสามารถควบคุมทุกแบบสอบถามที่คุณเขียนลงในตารางเพื่อตรวจสอบได้อย่างระมัดระวังคอลัมน์ของคอลัมน์จะทำงานให้คุณใน SQL 2012

เท่าที่คุณมีคำถามเฉพาะเกี่ยวกับคอลัมน์ข้อมูลประจำตัวฉันพบว่าคอลัมน์ข้อมูลประจำตัวบีบอัดได้ดีมากและขอแนะนำให้รวมไว้ในดัชนีคอลัมน์ของคุณในการทดสอบครั้งแรกของคุณ (โปรดทราบว่าหากคอลัมน์ข้อมูลประจำตัวเกิดขึ้นเป็นดัชนีคลัสเตอร์ของ b-tree ของคุณด้วยคอลัมน์นั้นจะถูกรวมไว้ในดัชนี columnstore ที่ไม่ใช่คลัสเตอร์ของคุณโดยอัตโนมัติ )

สำหรับการอ้างอิงต่อไปนี้เป็นขนาดที่ฉันสังเกตเห็นสำหรับ ~ 10MM แถวของข้อมูลคอลัมน์ข้อมูลประจำตัว Columnstore ที่โหลดสำหรับการตัดเซกเมนต์ที่เหมาะสมจะบีบอัดเป็น 26MB (เทียบกับ 113MB สำหรับการPAGEบีบอัดของตาราง rowstore) และแม้แต่ columnstore ที่สร้างขึ้นบน b-tree ที่สุ่มสั่งนั้นมีเพียง 40MB เท่านั้น ดังนั้นสิ่งนี้จึงแสดงให้เห็นถึงประโยชน์ของการบีบอัดขนาดใหญ่แม้การบีบอัด SQL แบบ b-tree ที่ดีที่สุดจะมีให้และแม้ว่าคุณจะไม่ต้องกังวลกับการจัดเรียงข้อมูลของคุณสำหรับการกำจัดเซกเมนต์ที่ดีที่สุด สร้าง columnstore ของคุณด้วยMAXDOP1)

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือสคริปต์เต็มรูปแบบที่ฉันใช้ในกรณีที่คุณต้องการเล่น:

-- 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

ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมตอนนี้ฉันตัดสินใจที่จะระงับจนกว่าฉันจะได้รับอย่างน้อย sql server 2014 เรากำลังก้าวไปสู่การอัพเกรดของเราดังนั้นฉันจึงหวังในปีหน้าหรือเพื่อที่เราจะสามารถทำได้
ดอน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.