在今天的文章里,我想專門詳細談下SQL Server 2014引入的可更新聚集列存儲索引(Updateable Clustered ColumnStore Index)。在我們進入細節討論前,我想先給你簡單介紹下它在SQL Server 2012里出現時的情況,還有它們的局限性。
SQL Server 2012里的列存儲索引SQL Server 2012里引入的列存儲索引是最熱的新特性之一(除AlwaysOn外)。如果使用得當的話,對于數據倉庫的工作負荷會帶來巨大的性能提升。遺憾的是,它們有2個大的局限性:
對一些用戶來說,這2個局限性是非常糟糕的。假設你有傳統行存儲數據的300GB表。使用列存儲索引是可以將數據壓縮到30GB大小。但SQL Server 2012只允許非聚集列存儲索引,這樣的話你需要2次存儲你的數據:一個在傳統行存儲格式里,另一個在新的列存儲格式里。那是存儲的巨大浪費,因為你的查詢只用到你的非聚集列存儲索引。
一旦你創建了你的非聚集列存儲索引,你就不允許修改表數據了——你的表就只讀了!當然,對這個問題有一些解決方法,例如分區交換,但你還是需要你自己來實現……
SQL Server 2014里的列存儲索引現在SQL Server 2014做出了一些改變,因為微軟已經解決了上述問題——用了一些魔法和幻想:SQL Server 2014提供你可更新的聚集列存儲索引(Updateable Clustered ColumnStore Index)!我們一起來具體看下在SQL Server里這個魔法和錯誤內部發生了什么。
第1個最重要的事實是:直接更新列存儲索引是不可能的!在你的INSERT,UPDATE和DELETE事務期間進行完全的解壓和壓縮太費時間了。因此SQL Server 2014從一些魔法里獲得幫助:Delta Stores和Delete Bitmap。我們詳細看下這2個概念。
每次當你只執行INSERT語句,新記錄不直接插入列存儲索引——記錄會插入Delta Store。Delta Store本身就是典型的B樹,有B樹的所有缺點和優點。接下來當你從列存儲索引讀取時,SQL Server同時從壓縮的列存儲索引和Delta Store里返回你數據。
當你執行DELETE語句時,在壓縮的列存儲索引里還是什么也沒發生。唯一發生的是通過Delete Bitmap記錄被邏輯刪除。在列存儲索引里的每條記錄在Delte Bitmap里都有對應位。當你再次讀取列存儲索引時,SQL Server會忽略在Delete Bitmap里標記為刪除的記錄。
執行UPDATE語句意味著在Delta Store里插入新的記錄,在Delete Bitmap里把原版本記錄標記為刪除。很簡單,是不是?下圖顯示了詳細展示這個概念(來源:http://research.microsoft.com/pubs/193599/Apollo3%20-%20Sigmod%202013%20-%20final.pdf):
因為Delta Store和Delete Bitmap讓你的列存儲索引看起來是可更新的,但事實上是不可變的。還有個叫做Tuple Mover的后臺處理,它定期運行最后把你的修改異步到列存儲索引。
在SQL Server 2014里,另外你終于可以定義聚集列存儲索引。這就是說你可以不需要將你的數據存儲在傳統行格式里。直接創建你的表,在上面創建聚集列存儲索引。用這個方法可以在存儲里節約大量空間,因為現在一切都是壓縮的。當你進一步和關系數據庫概念打交道時,聚集(Clustered)意味著已排序(Sorted)。但是使用聚集列存儲索引這句話是不對的:當你創建了聚集列存儲索引時,在你數據里是沒有排序的!請意識到這個小區別!
小結可更新的聚集列存儲索引是SQL Server 2014一個神奇的幻想。不要理解錯了:我是的確很喜歡用這個新特性引入的發展潛能,但你如果想要充分用好它,就要理解這個特性內部是如何實現的。
感謝關注!
新聞熱點
疑難解答