詳解數倉的向量化執行引擎

本文分享自華爲雲社區《GaussDB(DWS)向量化執行引擎詳解》,作者: yd_212508532。

前言

  • 適用版本:【基線功能】

傳統的行執行引擎大多采用一次一元組的執行模式,這樣在執行過程中CPU大部分時間並沒有用來處理數據,更多的是在遍歷執行樹,就會導致CPU的有效利用率較低。而在面對OLAP場景巨量的函數調用次數,需要巨大的開銷。爲了解決這一問題,GaussDB(DWS)中增加了向量化引擎。向量化引擎使用了一次一批元組的執行模式,能夠大大減少遍歷執行節點的開銷。同時向量化引擎還天然對接列存儲,能夠較爲方便地在底層掃描節點裝填向量化的列數據。列存 + 向量化執行引擎,是打開OLAP性能之門的金鑰匙之一!

關於行存、列存表

行存表按行存儲tuple到Page頁面。多用於TP場景,這些場景數據頻繁更新,增刪改操作多,查詢結果涉及表的多列。

行存表的存儲方式

列存表按列存儲,每列數據存儲到一個文件。多用於AP場景。

  • 表列數多,訪問列數少,減少IO操作次數
  • 列數據具有同質性,提高數據壓縮比
  • 基於列批量數據的運算,CPU的cache命中率高

列存表的存儲方式

執行框架

執行器是優化器與存儲引擎的交互樞紐。以優化器生成的執行計劃樹爲輸入,從存儲引擎訪問數據,並按照計劃,操作各種執行算子,從而實現數據的處理。採用Pipeline模式, 行執行器一次一tuple,列執行器一次一batch。上層驅動下層,使得數據在執行樹上流動。提供各種數據處理的執行算子。下圖展示了自上而下的控制流和自下而上的數據流。

執行器的Pipeline模式

執行器的執行過程可分爲這三個步驟:

  1. 執行器初始化:構造執行器全局狀態信息estate、遞歸遍歷計劃樹各節點,初始化其執行狀態信息planstate
  2. 執行器的執行:行引擎和向量化引擎入口獨立開,從計劃樹根節點開始,遞歸遍歷到葉節點獲取一個tuple/batch,經過逐層節點算子的處理,返回一個結果tuple/batch,直到再無tuple/batch。
  3. 執行器的清理:回收執行器全局狀態信息,清理各plan node的執行狀態。

執行器的執行過程

列執行器

行執行器的問題是:CPU大部分處理在遍歷Plan Tree過程,而不是真正處理數據,CPU有效利用率低。列存表獨有的應用場景,需要配套的向量化引擎,才能真正發揮其在OLAP場景下提升性能的優勢。因此,列執行器的改造基本思路爲:一次處理一列數據。

和行執行器一樣,向量化執行引擎調度器,遵循Pipeline模式,但每次處理及在算子間傳遞數據爲一次一個Batch(即1000行數據),CPU命中率提高,IO讀操作減少。列執行器的數據流結構VectorBatch如下圖所示。

列執行器數據流結構VectorBatch

行列混合:Adapter算子

列存表的某些場景不支持向量化執行引擎,譬如:string_to_array、listagg、string_agg等。
GaussDB具有將兩套行列引擎自動切換的能力。

行列引擎自動切換

針對列存數據,如果只有行引擎,通常需要將列數據重構成元組tuple給執行引擎逐行處理。Tuple deform過程影響列存數據查詢處理的性能。

向量化執行引擎的性能

對比行列存引擎對同一表達式x*(1-y)計算的性能,可以看到列存引擎的Cstore Scan算子相比行存引擎的Seq Scan算子,耗時減少了85%。

行/列引擎性能對比

向量計算的特點是:一次計算多個值,減少函數調用和上下文切換,儘量利用CPU的緩存以及向量化執行指令提高性能。

向量化執行引擎的性能優勢:

  • 一次一Batch,讀取更多數據,減少IO讀次數
  • 由於Batch中記錄數多,相應的CPU的cache命中率提升
  • Pipeline模式執行過程中的函數調用次數減少
  • 與列存表配套,減少tuple deform,即列存數據重構tuple的時間開銷

行/列執行器各算子對照

向量化引擎的執行算子類似於行執行引擎,包含控制算子、掃描算子、物化算子和連接算子。同樣會使用節點表示,繼承於行執行節點,執行流程採用遞歸方式。主要包含的節點有:CStoreScan(順序掃描),CStoreIndexScan(索引掃描),CStoreIndexHeapScan(利用Bitmap獲取元組),VecMaterial(物化),VecSort(排序),VecHashJoin(向量化哈希連接)等,下面將逐一介紹這些執行算子。

掃描算子

掃描算子用來掃描表中的數據,每次獲取一條元組作爲上層節點的輸入, 存在於查詢計劃樹的葉子節點,它不僅可以掃描表,還可以掃描函數的結果集、鏈表結構、子查詢結果集。一些比較常見的掃描算子如表所示。

算子(行/列存算子) 含義 出現場景
SeqScan/ CStoreScan 順序掃描 最基本的掃描算子,用於掃描物理表(沒有索引輔助的順序掃描)
IndexScan/CStoreIndexScan 索引掃描 選擇條件涉及的屬性上建立了索引
IndexOnlyScan/CStoreIndexOnlyScan 直接從索引返回元組 索引列完全覆蓋結果集列
BitmapScan(BitmapIndexScan, BitmapHeapScan) / CStoreIndexHeapScan (CStoreIndexAnd, CStoreIndexOr,CStoreIndexCtidScan) 利用Bitmap獲取元組 BitmapIndexScan利用屬性上的索引進行掃描,返回結果爲一個位圖;BitmapHeapScan從BitmapIndexScan輸出的位圖中獲取元組
TidScan 通過元組tid獲取元組 1.WHERE conditions(like CTID = tid or CTID IN (tid1, tid2, …)) ;2.UPDATE/DELETE … WHERE CURRENT OF cursor
SubqueryScan/VecSubqueryScan 子查詢掃描 以另一個查詢計劃樹(子計劃)爲掃描對象進行元組的掃描
FunctionScan 函數掃描 FROM function_name
ValuesScan 掃描values鏈表 對VALUES子句給出的元組集合進行掃描
ForeignScan/VecForeignScan 外部表掃描 查詢外部表
CteScan/VecCteScan CTE表掃描 掃描SELECT查詢中用WITH子句定義的子查詢

連接算子

連接算子對應了關係代數中的連接操作,以表 t1 join t2 爲例,主要的集中連接類型如下:inner join、left join、right join、full join、semi join、 anti join,其實現方式包括Nestloop、HashJoin、MergeJoin

算子(行/列存算子) 含義 出現場景
NestLoop/VecNestLoop 嵌套循環連接,暴力連接,對每一行都掃描內表 Inner Join, Left Outer Join, Semi Join, Anti Join
MergeJoin/VecMergeJoin 歸併連接(輸入有序),內外表排序,定位首尾兩端,一次性連接元組。等值連接 Inner Join, Left Outer Join, Right Outer Join, Full Outer Join, Semi Join, Anti Join
HashJoin/VecHashjoin 哈希連接,內外表使用join列的hash值建立hash表,相同值的必在同一個hash桶。等值連接 Inner Join, Left Outer Join, Right Outer Join, Full Outer Join, Semi Join, Anti Join

物化算子

物化算子是一類可緩存元組的節點。在執行過程中,很多擴展的物理操作符需要首先獲取所有的元組才能進行操作(例如聚集函數操作、沒有索引輔助的排序等),這是要用物化算子將元組緩存起來;

算子(行/列存算子) 含義 出現場景
Material/VecMaterial 物化 緩存子節點結果
Sort/VecSort 排序 ORDER BY子句,連接操作,分組操作,集合操作,配合Unique
Group/VecGroup 分組操作 GROUP BY子句
Agg/VecAggregation 執行聚集函數 1. COUNT/SUM/AVG/MAX/MIN等聚集函數;2. DISTINCT子句;3. UNION去重;4. GROUP BY子句
WindowAgg/VecWindowAgg 窗口函數 WINDOW子句
Unique/VecUnique 去重(下層已排序) 1. DISTINCT子句;2. UNION去重
Hash HashJoin輔助節點 構造hash表,配合HashJoin
SetOp/VecSetOp 處理集合操作 INTERSECT/INTERSECT ALL, EXCEPT/EXCEPT ALL
LockRows 處理行級鎖 SELECT … FOR SHARE/UPDATE

控制算子

控制算子是一類用於處理特殊情況的節點,用於實現特殊的執行流程。

算子(行/列存算子) 含義 出現場景
Result/VecResult 直接進行計算 1. 不包含表掃描;2. INSERT語句中只有一個VALUES子句;3. 當 Append/MergeAppend爲計劃根節點(投影上推)
ModifyTable INSERT/UPDATE/DELETE上層節點 INSERT/UPDATE/DELETE
Append/VecAppend 追加 1. UNION(ALL);2. 繼承表
MergeAppend 追加(輸入有序) 1. UNION(ALL);2. 繼承表
RecursiveUnion 處理WITH子句中遞歸定義的UNION子查詢 WITH RECURSIVE … SELECT … 語句
BitmapAnd Bitmap邏輯與操作 多維索引掃描的BitmapScan
BitmapOr Bitmap邏輯或操作 多維索引掃描的BitmapScan
Limit/VecLimit 處理LIMIT子句 OFFSET … LIMIT …

其他算子

其他算子包括Stream算子,以及RemoteQuery等算子

算子(行/列存算子) 含義 出現場景
Stream 多節點數據交換 執行分佈式查詢計劃,節點間存在數據交換
Partition Iterator 分區迭代器 分區表掃描,迭代掃描每個分區
VecToRow/RowToVec 列轉行/行轉列 行列混合場景
DfsScan / DfsIndexScan HDFS表(索引)掃描 HDFS表掃描

Gaussdb向量化的演進

在第一代向量化引擎之後,GaussDB演化出具有更高性能的向量化引擎:Sonic向量化引擎和Turbo向量化引擎。
GaussDB爲了OLAP執行性能提升,在列存 + 向量化執行引擎、批量計算的路上不斷演進:

  • Stream算子 + 分佈式執行框架,支持數據在多節點間流動
  • SMP,節點內多線程並行,充分利用空閒硬件資源
  • LLVM技術,全新的代碼生成框架,JIT(just in time)編譯器,消除tuple deform瓶頸
  • Sonic向量化引擎,對HashAgg、HashJoin算子進一步向量化,根據每列不同類型實現不同Array來對數據做計算
  • 新一代Turbo向量化引擎,對大部分算子做進一步向量化,在Sonic引擎的基礎上,新增了Null優化、大整數優化、Stream優化、Sort優化等,進一步提升了性能

總結

本文介紹了GaussDB向量化執行引擎,對其框架、原理、各算子概況、性能提升等做了詳細闡述。

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章