SQL Server 列存儲索引 第一篇:概述


SQL Server 列存儲系列:

在2017年,我第一次接觸列存儲索引(ColumnStore),數據庫環境是SQL Server 2012,微軟第一次在SQL Server 2012中推廣列存儲索引,到現在的SQL Server 2017環境,列存儲索引發生了很大的變化,舉個例子,當時的列存儲索引是不能更新的,只能先把刪除列存儲索引,再更新數據,最后重建列存儲索引。雖然使用十分不方便,但是查詢性能真的令人驚艷。

現在數據庫環境升級到了SQL Server 2017,要重新認識列存儲索引了。列存儲索引是數據倉庫中用於查詢和存儲大型事實表和維度表的標准實現,它使用基於列的數據存儲格式和高於傳統行存儲格式10倍的壓縮率,不僅使得列存儲索引得查詢性能比傳統的面向行的存儲高出約10倍,而且存儲空間得消耗會減少約10倍。

一,列存儲索引的基本概念

列存儲索引的實現機制,從頂層設計來說,是先把數據分組,在每一個分組中,再按照列來存儲數據。

1,列存儲、行存儲和增量存儲的概念

行存儲(Row Store):是傳統的數據存儲格式,以行格式來實現。在物理存儲上,數據按照行來存儲,一行包含所有的數據列。

列存儲(Column Store):是以列格式來存儲數據,各個列單獨存儲。列存儲索引實際上以列存儲格式來存儲“大多數”數據,部分數據以行存儲格式存儲。在列存儲格式中,數據以列為單位來壓縮和解壓縮,在一行數據中,對於需要的數據列進行解壓縮和查詢,而對於不需要的列,可以忽略,這樣可以快速掃描大型表的整個列。

增量存儲(Delta Store):是以行存儲格式存儲的聚集索引,列存儲索引會把一些數據存儲為行存儲格式,這些數據被稱為deltastore( 增量存儲區),它用於存儲在一次插入操作中因為數量太少而無法壓縮到列存儲中的行,每個增量行組都是通過行版本的聚集B-Tree索引來實現的。

2,行組(Rowgroup)

行組是基礎表中的一組數據行,這些數據行作為列存儲索引的一個片段,列存儲索引對該行組中的所有數據行做為一個整體進行壓縮和查詢。為了獲得高性能和高壓縮率,columnstore索引把表切成行組,然后對每個行組中的各個數據列進行壓縮。行組中的行數必須足夠大,閾值是100萬行,以提高壓縮率,壓縮之后的數據最終以列存儲格式進行存儲。

在列存儲索引中,行組主要分為列存儲行組和增量行組,列存儲索引同時包含這兩種類型的行組,

列存儲行組(columnstore rowgroup)是使用列存儲壓縮的行組,通常情況下,每個列存儲的行組的大小總是在100萬左右,這個大小不會隨着數據的增加而變化,也不會隨着數據的更新而發生劇烈的變化。

增量行組(delta rowgroup)是指以聚集的rowstore索引存在的行組,未經壓縮,總行數通常在100萬以下,用於臨時存儲更新的數據。

3,列段(column segment)

列段是由列存儲行組中的每一列構成的數據,對於每一個列存儲行組,每一列都有一個列段;每一個列段都壓縮到一起,存儲到硬盤上。

二,列存儲索引架構概述

聚集列存儲索引是整個數據表的物理存儲,為了減少列段的碎片並提高性能,columnstore索引可能會將一些數據臨時存儲到一個稱為deltastore的聚集索引中。

deltastore是一個以RowStore格式存儲的聚集索引,存儲的數據分為兩部分:一部分是新增的數據,另一部分是刪除的數據。

  • 對於新增的數據,該數據邏輯上存在於表中,但是,實際上,並不在列存儲中,而是以rowstore格式存儲在deltastore中。
  • 對於被刪除的數據,邏輯上被標記為刪除,但是,實際上,並沒有從列存儲中刪除,也就是說物理上沒有刪除,deltastore存儲的是被刪除的數據行的ID列表。

deltastore用於進行增量存儲,該操作在后台進行,對程序員是透明的。SQL Server基於性能的考慮,不會因為刪除或更新少數幾行數據,而去更新columnstore,但是會實時更新deltastore。為了返回正確的查詢結果,聚集的列存儲索引將列存儲和deltastore的查詢結果組合在一起,即把deltastore新增的行添加到結果集中,把deltastore中刪除的行從結果集中刪除,從而得到一個正確的結果。

1,增量行組(Delta Rowgroup)

增量行組是僅與列存儲索引一起使用的聚集B樹索引,它存儲數據行,直到行數量達到閾值(1,048,576行),然后把數據移入列存儲中,從而提高了列存儲的壓縮和性能。

當增量行組達到最大行數時,它將從“打開”狀態轉換為“關閉”狀態。一個名為元組移動器(tuple-mover)的后台進程會定時檢查封閉行組。如果該進程找到一個封閉的行組,那么它將壓縮增量行組,並將其作為COMPRESSED行組存儲到列存儲中。

在壓縮增量行組后,現有的增量行組將轉換為TOMBSTONE狀態,然后在無引用的情況下由元組移動器刪除。

2,增量存儲(deltastore)

列存儲索引的每個行組都可以具有一個增量行組,所有的增量行組統稱為增量存儲。

在大批量加載數據的期間,大多數行直接進入列存儲,而無需通過增量存儲。在批量加載結束時,或者執行INSERt操作時,由於插入行的數量太少,無法滿足列存儲的最小大小(102,400行),這些少量的數據行將進入增量存儲,而不是列存儲。 對於行數少於102,400的小型批量負載,所有行均直接進入deltastore。

3,非聚集列存儲索引

非集群列存儲索引和集群列存儲索引的功能相同,區別在於,非聚集索引是在行存儲表上創建的輔助索引,而聚集列存儲索引是整個表的主存儲。非聚集索引包含基礎表中部分或全部行和列的副本,索引被定義為表的一列或多列,並具有過濾行的可選條件。

三,列存儲索引的更新

加載(load)或插入(insert)的少量數據會直接進入deltastore,而不會進入到columnstore中。只有當deltastore中的數據行超過102,400行時,后台進程tuple-mover才會把數據壓縮、進而更新到columnstore中。

1,少量的數據加載和插入會直接進入deltastore

列存儲索引不是實時更新的,它通過緩沖區deltastore來臨時存儲數據,這樣做的目的是避免columnstore的頻繁更新,以提高性能。首先,只有當數據的更新數量超過閾值102,400行時,才會觸發列存儲索引的更新。

列存儲索引一次將至少102,400行壓縮到列存儲索引中,從而提高了列存儲的壓縮率和查詢性能。要以批量方式壓縮數據行,columnstore索引會累積少量加載(bulk)和插入(insert),並把數據插入到deltastore中。增量存儲操作在后台進行,為了返回正確的查詢結果,聚集列存儲索引將列存儲和增量存儲中的查詢結果組合在一起。

當行到達時,它們會進入增量存儲區:

  • 插入INSERT INTO ... VALUES語句。
  • 批量加載結束時,它們的數量少於102,400行。
  • 更新,每次更新都實現為刪除和插入。

增量存儲區還存儲已刪除行的ID列表,這些行已被標記為已刪除但尚未從列存儲中實際刪除。

2,把deltastore中數據更新到columnstore中

每一個delta rowgroup最多存儲1,048,576行,當delta rowgroup存儲的數據行達到該閾值時,delta rowgroup的狀態由OPEN轉換為CLOSED,一個名為元組移動器(tuple-mover)的后台進程檢查封閉行組。如果該進程找到一個封閉的行組,則將壓縮該行組並把其存儲到列存儲中。壓縮增量行組后,現有的增量行組將轉換為TOMBSTONE狀態,隨后在無引用的情況下由元組移動器刪除,並將新的壓縮行組標記為COMPRESSED狀態。

您可以使用ALTER INDEX重建或重新組織索引,以將增量行組強制進入列存儲。請注意,如果在壓縮過程中存在內存壓力,則列存儲索引可能會減少壓縮的行組中的行數。

3,列存儲索引的更新

對數據執行Insert、Delete和Update,列存儲索引是如何更新的?如下圖所示:

整體來看,NCCI的更新操作會比常規的BTree索引的維護成本更高。

對於Insert操作:插入NCCI的行將直接進入到增量行組(delta rowgroup),該行組在物理上組織為rowstore的聚集索引。為了使插入操作更有效率,增量行組中的行以未經壓縮的方式存儲。在SQL Server 2014中,增量行組進行PAGE壓縮。 在SQL Server 2016中,增量行組不會壓縮。

對於Delete操作:在執行delete命令后,首先把該行從rowstore表中刪除。其次從NCCI中刪除該行,由於NCCI確實沒有任何關鍵列,需要以某種方式有效地在NCCI中找到該行。

我們如何找到它?訣竅是使用聚集索引鍵列,或包含RID的堆(即沒有聚集索引的表)。這些列自動包含在NCCI中,即使沒有選擇它們作為NCCI定義的一部分,列存儲索引使用這些列把每個增量行組組織為聚簇索引。

要查找要刪除的行

  • 首先,SQL Server優先在每個增量行組(deltastore)中查找該行。如果找到該行,則把該行從增量行組中刪除。
  • 如果找不到該行,則該行存在於壓縮的行組中。由於沒有有效的方法來搜索壓縮的行組,因此把行標識符插入到稱為“刪除緩沖區”(delete buffer)的內部Btree中。該“刪除緩沖區”會定期合並到“刪除位圖”(delete bitmap)中。當訪問NCCI進行查詢時,這些行將被自動過濾。如果有大量的增量行組,則Delete操作可能會變得非常緩慢。

為了最大程度地減少NCCI的增量行組的數量,SQL Server以指數方式增長增量行組。例如,當行數達到100萬時,第一個增量行組將關閉。第二個增量行組達到100萬個標記,但是第一個增量行組尚未壓縮,我們在內部將閾值提高到200萬個。第三個增量行組以400萬個封閉,第二個以800萬個為上限,最大為3200萬個。即使增量行組可能有200萬行,但在壓縮時將其壓縮為100萬或更少的大塊,也就是說維持每個壓縮的行組的行數在100萬左右。

還要注意的另一點是,當從壓縮的行組中刪除一行時,它將導致索引碎片。 SQL Server 2016提供了一個在線操作來刪除已刪除的行。

對於Update操作:對NCCI進行更新等價於同時執行Delete和Insert操作,即使在增量行組(delta rowgroup)中找到數據行,也不會就地更新(in-place update)。

四,執行模式

SQL Server數據庫引擎使用兩種不同的處理模式來處理Transact-SQL語句:

  • 行模式執行(Row mode execution)
  • 批模式執行(Batch mode execution)

這兩個執行模式,分別用於查詢行存儲數據和列存儲數據,適用於不同的查詢類型,各有自己的優勢和劣勢。

1,行模式執行

行模式執行是與傳統數據表一起使用的查詢處理模式,其中數據以行格式存儲。SQL Server 引擎讀取所需行或索引的所有列,SQL Server從讀取的每一行中,檢索SELECT語句,JOIN謂詞或篩選器謂詞所引用的結果集所需的列。這種執行模式,會把所需行的所有列都讀取出來,即使有些列是不需要的,這種執行模式特別對於查詢少量數據特別有效,適用於少量數據的值查找(seek)。

2,批模式執行

批處理模式執行用於處理列存儲的數據,同時處理多行,因此稱為批處理。批處理中的每一列都作為矢量存儲在單獨的內存區域中,批處理模式還使用針對多核CPU優化的算法,並提高了現代硬件上的內存吞吐量。

批處理模式執行與列存儲存儲格式緊密集成並進行了優化,批處理模式在可能的情況下對壓縮數據進行操作,不需要對數據進行解壓縮就可以處理數據,這與行處理模式是截然不同的,相比行處理模式必須解壓數據才能對數據進行處理,批處理模式能夠獲得更好的並行性和更快的查詢性能。

當以批處理方式執行查詢並訪問列存儲索引中的數據時,SQL Server 引擎會在列段中同時讀取多行,但是SQL Server僅讀取結果所需的列,這些列由SELECT語句,JOIN謂詞或過濾器謂詞引用,對於數據行中的其他列,完全不需要讀取,這顯著地提高查詢的性能。

五,列存儲索引的優勢

列存儲索引能夠實現更高的數據壓縮率,通常是10倍於普通的數據存儲,顯著地降低了數據倉庫的存儲成本。對於數據分析,列存儲索引提供的查詢性能比B-Tree索引快一個數量級。鑒於這兩個原因,列存儲索引成為數據倉庫中用於數據存儲和數據分析的首選方案。

總體來說,對列存儲索引進行查詢,能夠獲得高效率的原因主要是:

  • 列存儲的值來自相同的值域或范疇,通常具有很多高度相似的值,這使得數據壓縮的效率非常高。進而減少了數據的存儲和讀取,最小化或消除了系統的I / O瓶頸,並顯着減少了內存占用。
  • 高壓縮率通過使用較小的內存占用空間來提高查詢性能,由於SQL Server可以在內存中執行更多查詢和數據操作,因此查詢性能可以提高。
  • 批處理執行模式在同一時刻會處理多行數據,通常將查詢性能提高2到4倍。
  • 查詢語句通常僅從表中選擇少量的幾列,相比行存儲,從表中讀取所有列,列存儲的格式減少了硬盤的總I / O。

 

 

參考文檔:

Columnstore indexes: Overview


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM