幾個月前,我們帶您了解了微軟下一代數據庫平台SQL Server Denali的列存儲索引功能。針對數據倉庫級別的表,它能夠在很大程度上改善查詢性能。在最新的社區預覽版CTP3中,我們有幸接觸到列存儲索引的完整功能,那麼在本文中,我們就將深入了解一下其中的奧秘。
同我們熟悉的“行存儲”格式不一樣,新的架構中每一列索引中的數據都是單獨分組並存放的,而列數據是可以被壓縮的。此外,當DBA在列存儲索引上運行一個查詢的時候,SQL Server只讀取查詢中使用到的列。這樣的結果就是:更少的磁盤I/O和更少的內存占用,所以查詢的性能將提升數十倍甚至一百倍。
對於列存儲索引和行存儲索引,我們在本文中做了一個對比測試,測試表中包含8500萬行數據,筆者使用了不同組合,而得出的結論同微軟SQL Server在線指南中的結果完全一致:
列存儲索引往往比行存儲索引要快。SQL Server在線指南中提到某些特定的情況下,行存儲索引的性能更好,但是大部分情況下毫無疑問是列存儲索引;
同預期的一樣,列存儲索引在使用聚合以及過濾的查詢中效果更佳;
查詢優化器會選擇列存儲索引比行存儲索引速度更快;
查詢執行時間根據不同的應用場景,可能會快上幾十倍或者上百倍。列中重復的value越多,那麼說明它的壓縮率就越高,因此得到的性能提升也更高。同樣地,對於數據類型來說也是如此;
構建一個列存儲索引同行存儲索引所需要的時間幾乎相同。在CTP2版本中,所有的微軟MVP試用者都反映列存儲索引的構建時間要長一些。但是在CTP3中,微軟已經對這一功能進行了改進。
考慮一個特殊的場景:一個查詢返回結果中有兩列,其中value的區別不大;結果集包含850行。使用傳統的行存儲索引,查詢大約花掉了4分鐘時間,而使用列存儲索引,執行時間降到了1.2秒,速度提升了200倍。此外,測試的Denali Server是一個虛擬機,沒有對磁盤I/O進行過優化。
妥善使用列存儲索引
列存儲索引並不是完美無暇,它也有自身的限制。每一個表當中只能由一個列存儲索引,如果使用表分區,那麼你必須在索引中包含分區列。不能包含以下的數據類型:二進制、可變二進制、文本、備注、圖像、varchar(max)、nvarchar(max)、唯一標識符、時間戳、精度大於18位的小數和數字、CLR以及XML。
除了數據類型限制之外,SQL Server Denali列存儲索引中最大的限制是:一旦你創建了一個列存儲索引,表就變成只讀了,因此任何不能再做任何的數據修改。這對於任何一個更新頻繁的表來說都是不太好的消息。
微軟對此還要做出相應的調整,目前最直接的方法就是只能在預先設置的時間內更新表。刪除或者廢除索引,然後在更新之後進行重建。
或者可以使用分區。使用insert添加一個新的分區,想要更新現有行的時候,再斷開,drop列存儲索引,更新數據,重現創建索引然後再添加到表中。
最後的方法,就是將數據分片成靜態數據然後進行更新。保持列存儲索引表中的靜態數據,然後將需要更新的數據存儲在不同的索引表當中。使用UNION ALL語句來從這兩種表中進行select。使用這種方法,也能獲得部分效果:靜態數據表中的列存儲索引可以加快查詢速度,而另外的傳統表格則速度不會提升。
當然,這樣的情況並不是十分常用,主要適用於數據倉庫表或者不經常使用的在線交易處理表等。在SQL Server在線指南中提醒我們慎重使用列存儲索引,而這部分功能在未來的正式版中可能會有所改動。所以我們可以推測,在正式版本的SQL Server Denali中,我們將不會受到這樣的限制。
SQL Server Denali的列存儲索引功能在特定環境中的效果十分明顯,特別是數據倉庫。查詢性能上的改進意味著在實際運行中的查詢時間將大幅縮短,而我們不需再使用靜態數據的聚合表,然後定期刷新了。在使用之前充分考慮公司的具體業務需求,將能達到事半功倍的效果。