具體的bwtree的算法能夠看:http://www.cnblogs.com/Amaranthus/p/4375331.htmlhtml
每一個行組,SQL Server都會使用Vertipaq壓縮算法,從新編碼和排列行組中的順序來打到最有的壓縮效果。每一個行組中的列都是獨立保存的,這個結構稱之爲段(segment),每一個段都是一個LOB,保存在LOB的分配段元中。段是數據讀寫的基本單元,如圖,表示吧一組多個索引列轉化爲幾個段算法
上圖中,表被分爲3個行組,每一個行組有4個段,一共有12個段。數據結構
爲了支持彙集行存儲索引的更新,有2個額外的結構。一個獨立的內部表(deleted rows table DRT)。顧名思義是用來作被刪除行的bitmap,用來保存全部已經刪除的行的rowid。新行加入會被保存在一個堆中,Delta Store。當行數達到必定行數(一般是2^20或者10萬行),SQL Server會吧這些行轉化爲新的壓縮的行組。併發
內存優化表中彙集列存儲索引和內存優化表的非彙集索引是分開保存的,是數據的一個副本。實際上,內存優化表的彙集列存儲索引你能夠理解爲,保存了全部列的非彙集列存儲索引。由於數據是高效壓縮的,所以開銷比較少。由於類存儲索引能夠壓縮到原始數據的10%,所以開銷也只有10%。app
全部的類存儲索引段都是在內存中的。爲了恢復的目的,每一個行組在內存優化文件組中都保存成一個獨立的文件類型爲LARGE DATA,在文件中對於某個行組,全部的段都是存放在一塊兒的。SQL Server也維護了一個指針,指向每一個段而且能夠訪問這個段,特別是訪問了部分列的時候。這個部分會在下面CHECKPOINT FILES的時候介紹。新的行會被以列存儲索引保存,可是並不會立刻加入到壓縮行組中,新的行只能使用內存優化表的其餘索引來訪問。如圖,新的行和整個表分開維護的。你能夠認爲這些行是「delta rowgroup」和磁盤表的Delta Store相似,可是這些行是內存優化表的一部分,可是不是技術上的列存儲索引的一部分。其實是課件的delta rowgroup性能
內存優化表中的列存儲索引只能在interop模式下由優化器進行選擇。查詢使用類存儲索引能夠併發而且對於高性能有不少好處。原生編譯過程是不會使用列存儲索引的,而且全部的查詢都不會併發執行。若一個SQL Server 2016的內存優化表有彙集列存儲索引,那麼就有2個varheap,一個用於壓縮行組,另一個用來保存新行,可讓SQL Server快速識別哪些行尚未進入壓縮段,這些行也在可見的delta rowgroup中。優化
有2個後臺線程每2分鐘執行一次,用來檢查delta rowgroup中的行。注意這些行包含最新插入的,和update的,在內存優化表update就是delete+insert。若是這些行數超過10萬那麼就有下面2個操做:編碼
SQL Server並不會是實際統計行數,而是使用評估。沒有行組的行數能夠超過1048576.若是超過有10萬行,那麼就會建立另一個行組。若是小於10萬行那麼這些行仍是會被留在原來的地方。spa
由於最新插入的行會被頻繁更新,或者會被刪除,想要延遲對最新行的壓縮,能夠設置一個等待量。當內存優化表有彙集列存儲索引,那麼就能夠增長一個COMPRESSION_DELAY的參數,指定新行必須在delta rowgroup中呆多久。只有超過參數的行數超過10萬纔會被壓縮到常規的列存儲索引行組中。線程
當行被轉換到壓縮rowgroup以後,全部刪除的行都會被放到Delete Rows表中,和磁盤表的彙集列存儲索引。當行多的時候查詢會很沒有效率。這種狀況下重組列存儲索引並無什麼用,除非刪除而且重建索引。一旦rowgroup中90%的行被刪除,剩下的10%會自動被插入到未壓縮的varheap,在內存優化表的Delta rowgroup中。Rowgroup的存儲會被進行垃圾回收。
Note:
前面提到的,若是內存優化表有任何LOB或者溢出列,列存儲索引不能在上面被建立。由於最大的行不能超過8060字節。另一旦內存優化表有一個列存儲索引,就不能使用alter table操做。須要先刪除列存儲索引,alter,而後再建立列存儲索引。
如下是建立內存優化表的腳本,有2個索引,一個range索引一個列存儲索引,而後查詢內存消費。而且設置COMPRESSION_DELAY爲60分鐘。
AND c.index_id = i.index_id;
返回的結果:
上圖,顯示錶本身有6行。有一個內存消費者用於壓縮rowgroup(HKCS_COMPRESSED消費者),2個用於range index,1個用於hash index,2個用於表的行存儲(rowstore)(這個和白皮書中說的不一樣),行存儲中其中一個是爲了表中的行,第二個是delta rowgroup。每一個有列存儲索引的表都有4個內部表,xtp_object_id都不相同。每一個內部表爲了訪問方便至少有一個索引用於數據訪問。四個內部表:ROW_GROUP_INFO_TABLE(+hash索引),SEGMENTS_TABLE(+2個hash索引),DICTIONARIES_TABLE(+hash 索引),DELETED_ROW_TABLE(+hash索引)。(這些內部表的細節白皮書沒有介紹)
除了看內存消費者以外,另一個要檢查的DMV是sys.dm_db_column_store_row_group_ physical_stats,這個視圖不僅僅是顯示了每一個COMPRESSED而且OPEN的rowgroup的行數。你能夠用一下腳本查看:
能夠經過time_reason_desc字段能夠查看爲何rowgroup的行會少於1048576行。若是沒有小於1048576那麼就顯示NO_TRIM。由於OPEN的rowgroup是不壓縮的,所以爲null,若爲STATS_MISMATCH表示行太少,若爲SPILLOVER表示有移除致使。