SQL Server 列儲存索引 第二篇:設計

悅光陰發表於2020-10-30

列儲存索引可以是聚集的,也可以是非聚集的,使用者可以在表上建立聚集的列儲存索引(Clustered Columnstore Index)或非聚集的列儲存索引(Nonclustered Columnstore Index)。由於聚集索引實際上是表的物理儲存,因此,表上只能建立一個聚集索引,該聚集索引要麼是聚集的列儲存索引,要麼是聚集的行儲存索引。由於非聚集的索引(列儲存索引和行儲存索引),是在表的物理儲存空間之外額外建立的資料結構,因此一個表可以建立多個非聚集的索引。

由於列儲存索引相比普通的B-Tree索引,提高約10被的壓縮率和查詢效能,因此,對於資料倉儲的大型資料表,都可以建立列儲存索引。而列儲存索引實際上是由兩部分構成的:列儲存區(columnstore)和增量儲存區(deltastore),並且會產生索引的碎片,在建立列儲存索引時,需要根據表的更新頻率和查詢的需求(是值查詢,還是分析查詢)來為表設計合適的索引。

一,索引的設計思路

在建立索引時,對於一個表:

  1. 如果已經建立了聚集的列儲存索引,那麼該表上不能再建立非聚集的列儲存索引,但是可以建立非聚集的行儲存索引。
  2. 如果已經建立的聚集的行儲存索引,那麼該表上可以建立一個或多個非聚集的列儲存索引,也可以建立一個或多個非聚集的行儲存索引。

列儲存索引特別適合進行大量資料的分析查詢,而行儲存索引適合用於少量資料值的查詢。

聚集的列儲存索引是整個表的物理儲存,通常把聚集的列儲存索引稱作列儲存表,而非聚集的列儲存索引是在表的物理儲存之外額外建立的資料結構,非聚集的索引包含基礎表中部分或全部的資料行,也可以只包含部分列,即,列儲存索引被定義為表的一列或多列,並具有過濾行的可選條件。

推薦的設計思路:

  • 使用聚集的列儲存索引(把錶轉換為列儲存)來儲存事實表和大的維度表,用於提高查詢效能和資料壓縮效能,提高的效能大概在10倍左右。
  • 在行儲存表上,使用非聚集的列儲存索引對資料進行分析查詢。

二,把列儲存和行儲存結合到一起

從SQL Server 2016 (13.x)版本開始,列儲存索引和行儲存索引可以結合在一起,利用這兩種型別的索引的優點,提高查詢效能、並減低儲存消耗。

使用者可以在rowstore表上建立一個或多個可更新的非聚集列儲存索引(updatable nonclustered columnstore index),該索引儲存所選列的副本,因此需要額外的空間來儲存此資料,但是所選資料平均被壓縮10倍。使用者可以在列儲存索引上執行分析,同時在行儲存索引上執行事務。當行儲存表中的資料更改時,列儲存將更新,因此兩個索引都針對相同的資料工作。

使用者可以在列儲存表上建立一個或多個非聚集的行儲存索引,並在基礎列儲存上執行有效的表查詢。

三,設計方案

方案1:建立聚集的列儲存索引

表通常是行儲存的,為表建立一個列儲存索引,就把錶轉換為列儲存格式。聚集的列儲存索引不僅僅是一個索引,實際上,聚集的列儲存索引就是資料表的物理儲存,能夠提高10倍的壓縮率和資料查詢效能。

當表滿足以下條件,考慮建立聚集的列儲存索引:

  • 對於分割槽表來說,每個分割槽至少100萬行資料,列儲存索引在每個分割槽中都有行組,如果表太小而無法在每個分割槽中填充行組,則無法獲得列儲存壓縮和查詢效能的好處。
  • 查詢主要對值範圍執行分析,例如,要查詢列的平均值,查詢需要掃描所有列的值,然後,通過將它們求和以確定平均值來彙總這些值。
  • 大多數插入的資料量是海量的,而更新和刪除操作最少。 

相反,如果每個分割槽少於100萬行資料,或者表上的更新和刪除操作非常多(更新操作會導致碎片),或者含有LOB欄位,即包含 varchar(max), nvarchar(max) 和 varbinary(max)資料型別,那麼不要建立聚集的列儲存索引。

方案2:在聚集的列儲存索引上建立非聚集的行儲存索引,用於少量值得查詢

從SQL Server 2016(13.x)開始,使用者可以在聚集得列儲存索引上建立非聚集得B-Tree索引,當列儲存索引發生更改時,非聚集得B-Tree索引也會更新。通過使用輔助的B樹索引,使用者可以有效地搜尋特定行,而無需掃描所有行。

方案3:使用非聚集的列儲存索引進行實時分析

從SQL Server 2016(13.x)開始,使用者可以在行儲存表(Disk-Based表或記憶體記憶體優化表)上建立非聚集的列儲存索引,使得使用者可以在事務表上進行實時分析。在基礎表上進行事務處理時,資料會更新到列儲存索引上,使用者可以在列儲存索引上進行分析性的查詢。由於一個表同時管理兩種型別的索引,因此,行儲存索引和列儲存索引都可以實時進行更新。由於列儲存索引的資料壓縮效能比行儲存索引高約10倍,因此只需要少量的額外儲存。例如,如果壓縮的行儲存表佔用20 GB,則列儲存索引可能需要額外的2 GB。所需的額外空間還取決於非聚集列儲存索引中的列數。

四,分割槽對列儲存的影響

可以對分割槽表建立列儲存索引,對於每一個分割槽,都有一個或多個行組,可以認為對每個分割槽單獨建立列儲存索引。由於列儲存索引對資料量有一個顯式的要求,100萬行,如果每個分割槽沒有一百萬行,那麼大多數資料行可能會轉到增量儲存,而在增量儲存中它們將無法獲得列儲存壓縮的效能優勢。除非你有足夠大的資料量,否則,為列儲存索引使用更少的分割槽。

舉個例子:

  • 將100萬行載入到一個分割槽或未分割槽的表中,您將獲得一個包含100萬行的壓縮行組,這對於高資料壓縮和快速查詢效能非常有用。
  • 將100萬行平均載入到10個分割槽中,每個分割槽獲得10萬行,這比列儲存壓縮的最低閾值還小,這導致列儲存索引可能有10個增量行組,每個組有10萬行。

雖然有一些方法可以把增量行組強制進入列儲存,但是,如果這些是columnstore索引中僅有的行,則壓縮的行組將太小而無法獲得最佳的壓縮和查詢效能。

五,選擇合適的資料壓縮演算法

列儲存索引為提供了兩種資料壓縮的演算法:列儲存壓縮(columnstore compression)和存檔壓縮(archive compression)。 使用者可以在建立索引時選擇壓縮選項,稍後使用ALTER INDEX ... REBUILD對其進行更改。

1,使用列儲存壓縮以獲得最佳查詢效能
與行儲存索引相比,列儲存壓縮通常可實現10倍更好的壓縮率。 它是列儲存索引的標準壓縮方法,可實現快速查詢效能。

2,使用存檔壓縮以獲得最佳資料壓縮
當查詢效能不太重要時,歸檔壓縮旨在最大程度地壓縮資料,與列儲存壓縮相比,它實現了更高的資料壓縮率,但代價不菲。 壓縮和解壓縮資料需要更長的時間,因此不適合快速查詢效能。

 

 

參考文件:

Columnstore indexes - Design guidance

相關文章