列存儲場景
Ⅰ ColumnStore index (列存儲索引)解析
首先,介紹列存儲的概念:在傳統資料庫存儲中,數據採用行存儲方式。例如,在SQL Server中,每個頁面大小為8KB,若每條數據長度為500位元組,理論上可以存儲大約16條數據,每條數據包含了所有欄位的信息。如圖所示,多個頁面存儲了成行數據。
接下來,介紹列存儲,數據以列的形式存儲,而不是以行的形式。在SQL Server中,數據向行組或段存儲。例如,假設表有5個欄位(列),每個紅色柱體代表一個段,每5個段組成一個行組。每個段僅包含一個列的數據,而行組包含所有列的數據。
每個段最多可以存儲100萬條該列的數據,從性能角度來看,100萬條數據可以實現最優性能,數據量較少時,段的性能會降低。
列存儲與行存儲相比,列存儲在數據倉庫場景下表現更佳,數據倉庫用戶數量較少,數據量巨大,數據變化較少。列存儲能將大量數據壓縮到1/10,從而減少I/O、CPU和內存使用,提高性能。此外,列存儲還採用了批量模式、段消除等技術,對性能有很大提升。
列存儲適合以下場景:
使用星型/雪花模型構建的數據倉庫
表(或分區)記錄數大於100萬
主要執行報表類SQL查詢,而非鍵查找
數據更新和刪除操作較少,大量插入操作可行
表中沒有VARCHAR(MAX), NVARCHAR(MAX), 或 VARBINARY(MAX) 數據類型
在某些特定的OLTP資料庫場景下,如實時操作分析,列存儲也可適用
列存儲的物理結構包括行組和delta存儲。假設表有1105萬條記錄,每個行組容納100萬條,總共有11個行組,剩餘5萬記錄存儲在delta存儲中。delta存儲用於存儲不足100萬條數據的行存儲數據,而行組採用列存儲且進行了壓縮。
隨著插入數據增加,delta存儲的數量增加,當數量達到100萬時,delta存儲停止接收數據,轉換為行存儲並進行壓縮。如有更多數據插入,生成新的delta存儲。
列存儲結構包括行組、delta存儲、和刪除點陣圖。刪除記錄並非物理刪除,而是邏輯刪除,通過在刪除點陣圖中添加標記記錄被刪除的記錄。在SQL Server查詢時,除了查詢行組和delta存儲的數據,還需要查詢刪除點陣圖,將三者結果進行合並。
當進行索引重建或重組時,列存儲才會進行物理刪除。在更新列存儲時,不是物理更新,而是刪除記錄後插入新的記錄。
列存儲小結:包括壓縮的列存儲行組、行存儲delta存儲、以及存儲被刪除記錄信息的刪除點陣圖。從SQL Server 2016開始,可以創建列存儲索引的同時,創建傳統行存儲的非聚簇索引(NCI)。列存儲本身不排序,查詢特定記錄時需要全表掃描,插入操作性能較好,但刪除和更新操作的代價較大,特別是對於大型表。
為了確定某些表是否適合創建列存儲索引,可以參考以下條件:表需要足夠大,至少100萬條記錄,且大部分SQL查詢為報表類查詢,update和delete操作較少。可以通過查詢DMV sys.dm_db_index_operational_stats來判斷表是否適合創建列存儲索引。
在SQL Server 2019中,可以使用sp_estimate_data_compression_savings預估創建列存儲索引後的壓縮率。快速載入數據到已創建列存儲索引的表中,可以採用外部文件批量導入、從其他表導入數據或使用SSIS,SQL Server會自動使用並行操作。
列存儲的性能提升來自壓縮、批量模式、段消除和並行處理。批量模式允許一次處理大量數據,適合大數據量的數據倉庫。段消除和列消除自動過濾掉不相關的行組和段,提高查詢效率。對於匯總函數,如SUM、AVG等,列存儲支持批量處理,減少數據傳輸量,提高性能。
列存儲的維護包括碎片處理。列存儲的碎片類型有兩種:delta存儲碎片和行組碎片。delta存儲碎片超過10個時需要維護,行組碎片超過10%時,需要進行物理刪除處理。
從SQL Server 2016開始,可以使用ALTER INDEX命令中的自合並(self merge)和合並(merge)操作來維護列存儲索引。自合並操作在行組的邏輯刪除記錄超過10%時,會物理刪除這些記錄;合並操作將兩個行組的記錄合並,當它們的總記錄數不足100萬時。
列存儲與內存資料庫技術結合,應用於實時操作分析場景。這類場景結合了OLTP和數據倉庫的特點,使用內存表和磁碟表進行數據存儲,分別適用於OLTP和報表查詢。內存表和列存儲索引共同存儲數據,提高查詢性能和數據處理效率。在該場景中,需要大量內存空間,而實時操作分析可以利用這兩種技術的優勢,實現高性能的數據處理。