SQL Server內置的HTAP技術
目錄
- 背景
- SQL Server在OLAP上的發展
- SQL Server的初代HTAP
- SQL Server逐漸增強的HTAP
- SQL Server列存總結
- HTAP發展
背景
2005年,Gartner正式提出了HTAP這一概念,並且迅速引起了一些企業的關注,被視為是未來數據發展的重要趨勢之一。
到了2014年,Gartner又對HTAP數據庫給出了明確的定義:混合事務/分析處理(HTAP)是一種新興的應用體系結構,兼容兩種業務場景。
混合負載(HTAP Hybrid Transactional/Analytical Processing)是在保留原有在線交易功能的同時,強調了數據庫原生計算分析的能力。
HTAP體系架構解決的一個問題是 傳統的數據倉庫做數據分析的時效性問題,傳統數據倉庫架構需要用ETL工具從各種業務數據源(oltp)抽取數據到數據倉庫(olap)進行跑批分析,這個時效大概是T+1。
傳統數據類項目,如數據倉庫、數據集市等其他數據應用類項目有跑批日期的概念,即在T+1日跑T日的交易數據,直白的說就是在第二天跑昨天的交易。
T指的是每天或者每一個交易日,我們經常說的跑批日期也是T日的數據。
無論是過去的傳統數倉,還是現在的大數據技術棧,都存在這個時效性問題。HTAP體系架構的做法是,同時支持OLTP和OLAP場景,基於創新的計算存儲框架,在同一份數據上保證事務的同時支持實時分析,省去費時的ETL過程。
SQL Server在OLAP上的發展
過去,SQL Server自帶完整的數倉服務套件 ,方便用戶搭建傳統數倉,SQL Server企業版和數據中心版本身提供了三個服務
- 做數據ETL的SQL Server集成服務(SSIS)
- 做報表的SQL Server報表服務(SSRS)
- 做數據多維分析的SQL Server 分析服務(SSAS olap引擎)
相信大家在SQL Server安裝界面看到過上面幾個服務的安裝選項。
后來,為了處理更大的數據量,微軟推出SQL Server並行數據倉庫(PDW),使用多個SQL Server數據庫服務器在大規模並行處理架構下存儲和處理數據。
再到最近十年,隨着大數據技術棧發展迅猛,微軟推出PolyBase用來整合SQL Server和Hadoop。
但是,以上技術還是需要ETL過程,存在時效性問題。
SQL Server的初代HTAP
初代HTAP首次出現在SQL Server2012版本,最初設計的目標,僅僅為了在OLTP中提供數倉場景下的OLAP能力,讓用戶可以直接在一個DBMS的行存表上建列存索引然后執行分析型負載,省去費時的ETL過程。
面對這樣的目標,SQL Server2012提供的是一個面向OLAP的列存引擎,對應上層的接口就是Read-Only Columnstore Index,即在一個行存表上建立列存索引之后,這個表變為只讀。
列存的存儲格式很簡單,每100萬行組成一個Row Group,Row Group中每一個字段組成一個Column Segment,每個Column Segment的元數據存儲在系統表中。列存索引只提供全表掃描。
圖3-1
這樣的設計,有兩個問題:
- 整個表都不支持更新,只讀狀態
- 列存索引只能是非聚集列存索引,不能是聚集列存索引
SQL Server逐漸增強的HTAP
到了SQL Server2014和SQL Server2016這兩個版本,微軟逐漸增強了列存引擎的能力,解決了初代HTAP的兩個缺點,開始支持更新,並支持表中只有列索引一份數據即聚集列存索引。
這時候,一個數據庫融合了3種存儲引擎,分別是:
- Apollo引擎:列存引擎,面向olap
- 傳統引擎:行存引擎,面向oltp,B+樹或堆結構
- hekaton引擎:純內存行存引擎,面向oltp ,bwtree結構
圖4-1
圖4-2
為了支持更新,SQL Server引入了delta store、delete flag、rowid。
Delete Flag
在列存索引里刪除一行數據時,實際上只是對這行數據加一個delete flag標記(bitmap標記),並不會物理刪除這行數據
Delta Store
是相對磁盤上的列存Main Store來說的,用於緩存Insert。
Delta Store由Delta rowgroup實現,所有Delta rowgroup都統稱為Delta Store,有些文獻也叫tail index(下文中Delta Store 和 Delta rowgroup是同一個意思)
所有的rowgroup也統稱為Main Store(下文中Main Store 和 rowgroup是同一個意思)
Delta Store在結構上是聚集 B樹索引,提供熱數據的原地更新刪除,為Main Store做緩沖。
RowID
由列存引擎生成,用來在列存索引中唯一標記一行數據。
列存rowid在數據行插入到rowgroup時候生成,這個rowid一直到數據行被刪除都不會改變。
當行存和列存組合時,需要在行存添加一個字段來存儲這個列存rowid,這樣來使列存和行存通信。
行存中存儲全量數據,列存分為Delta Store和Main Store,其中Main Store以列存的形式存儲絕大部分數據,以Row Group為單位划分,每個Row Group對應行存中一定數量的記錄。
假設用戶建了一個行存索引和列存索引組合的表,事務插入數據時,會同時插入行存和Delta Store,Delta Store達到100W行閾值后凍結,tuple-mover后台線程會將其中較冷的數據遷移到Main Store,
冷熱數據通過統計信息來判斷。遷移過程中也會由新的Delta Store來緩存Insert。
遷移分為兩個階段:
- 第一階段:在一個事務中完成,將Delta Store冷記錄遷移到Main Store,在Main Store中把遷移過來的冷記錄標記delete flag刪除並分配RowID。事務提交后遷移的部分在列存索引中不可見,但在Delta Store中依然可見,數據是一致的,這時Delta Store中冷記錄並沒刪除。
- 第二階段:在一些小事務中完成,每個事務將第一階段遷移的冷記錄從Delta Store中刪除,一個事務刪一條記錄,將對應的RowID更新到行存,並在Main Store中刪除這條記錄通過delete flag標記,事務提交后這條記錄在列存索引中可見,但在Delta Store中不可見,數據也是一致的。
SQL Server從兩個方面來減少數據遷移對行存性能的影響
- 第一方面:第二階段更新行存中RowID時不記日志,數據庫故障恢復時通過掃描列存重建行存RowID,減少日志開銷。
- 第二方面:第二階段每個事務只處理一條記錄,減少與前台事務的寫-寫沖突(將對應的RowID更新到行存,如果有別的前台事務也要update行存的這條記錄,會造成寫-寫沖突)。
事務刪除數據時,如果記錄在Delta Store中,則直接在行存和Delta Store中刪除,如果記錄在Main Store中,則需要根據行存中存儲的RowID在Main Store中通過全表掃描把對應記錄通過delete flag標記刪除。
為了優化全表掃描刪除的性能,SQL Server引入了Delete Buffer,將多個刪除緩存,然后在一次全表掃描中批量刪除
圖4-3
圖4-4
Main Store中標記刪除的記錄太多也會影響scan的性能,也會帶來額外的內存開銷,因此需要后台自動進行reorganize索引或由用戶自己rebuild索引。
列存索引的重整由Row Group中標記刪除的比例觸發(90%),由tuple-mover后台線程將觸發重整的Row Group中的有效記錄重新插入Delta Store中,而被重整的Row Group則被tuple-mover回收。
事務更新數據時,通過先刪除 + 后插入實現,上文已經說了刪除 和插入的實現方式,這里不再敘述。
事務查詢數據時,列存引擎需要掃描Main Store,並根據delete flag剔除已刪除數據,當第一次建列存索引時,列存引擎還需要通過Delta Store從行存表中獲取未遷移到Main Store的數據,
然后利用bulk load,把未遷移到Main Store的行存數據(滿足100w行的條件)直接遷移到Main Store,如果數據不足100w行,那么就把行存數據遷移到Delta Store中
因此,query數據時,要查詢Delta Store和Main Store,把兩者的結果Union才是最后的結果。
圖4-5
SQL Server列存總結
在概括SQL Server列存設計的優缺點之前,首先要看下數倉場景下更新的特點,這會影響到整個存儲設計。
數倉場景下更新的特點,更新中絕大部分的是Insert,只包含極少數的Update和Delete。
並且列存中in-place update的成本很高,所以Update的實現一般是一次Delete加上一次Insert 這種out-of-place update。因此支持更新實際上只需要考慮Insert的性能,Delete的性能並不是很重要。
現在大部分的列存引擎普遍都會選擇Delta-Main架構,因為本身按列存儲就不利於更新,因此需要使用Delta緩存架構來解決更新的問題。
SQL Server列存的優缺點
優點:
- 通過引入delta store、delete flag、rowid,讓列存索引以append-only的方式更新,保證跨行存和列存索引上事務的ACID。
缺點:
- 插入數據到列存、Row Group重整、更新列存數據帶來一定開銷,這個開銷就是都需要更新行存中的RowID,因此都會和行存的OLTP事務產生競爭,影響系統整體性能,這個是SQL Server行存和列存緊耦合導致的。
根據數倉場景的特點,SQL Server列存的開銷其實可以接受,然后使用類Delta-Main架構也是比較主流的做法,但是到了HTAP的場景,整個數據庫需要支撐高並發的查詢和更新,列存的開銷就會被放大。
在這方面,SQL Server也提供了很多優化方案,比如使用Mapping Index來減輕更新行存中的RowID的開銷問題。
有同學會問SQL Server2014開始支持聚集列存索引,整個表只有一個列存索引作為primary index,就不會有更新行存RowID這個開銷,但是數據庫一般也需要唯一約束、外鍵約束等,要維護這些約束就需要行存B樹索引來輔助。
所以,最后還是要行存和列存組合來使用。
HTAP發展
最后,從SQL Server的發展來看,一份表數據兩種存儲格式,兩種存儲引擎處理,查詢時優化器自動選擇存儲引擎執行,對用戶透明,這些特性讓SQL Server走在了前列
當然,其他商業數據庫和開源數據庫也在向HTAP方向發展,例如Oracle、GreenPlum、SAP HANA等等
還有,兩大開源國產數據庫代表PingCAP、OceanBase,在成立之初就定位為新一代分布式的HTAP數據庫,通過行存和列存松耦合來解決性能問題,新型的分布式架構確實比傳統數據庫更勝一籌。
本文版權歸作者所有,未經作者同意不得轉載。