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

华为云开发者联盟發表於2024-04-25

本文分享自華為雲社群《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向量化執行引擎,對其框架、原理、各運算元概況、效能提升等做了詳細闡述。

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

相關文章