本文分享自華為雲社群《GaussDB(DWS)向量化執行引擎詳解》,作者: yd_212508532。
前言
- 適用版本:【基線功能】
傳統的行執行引擎大多采用一次一元組的執行模式,這樣在執行過程中CPU大部分時間並沒有用來處理資料,更多的是在遍歷執行樹,就會導致CPU的有效利用率較低。而在面對OLAP場景巨量的函式呼叫次數,需要巨大的開銷。為了解決這一問題,GaussDB(DWS)中增加了向量化引擎。向量化引擎使用了一次一批元組的執行模式,能夠大大減少遍歷執行節點的開銷。同時向量化引擎還天然對接列儲存,能夠較為方便地在底層掃描節點裝填向量化的列資料。列存 + 向量化執行引擎,是開啟OLAP效能之門的金鑰匙之一!
關於行存、列存表
行存表按行儲存tuple到Page頁面。多用於TP場景,這些場景資料頻繁更新,增刪改操作多,查詢結果涉及表的多列。
列存表按列儲存,每列資料儲存到一個檔案。多用於AP場景。
- 表列數多,訪問列數少,減少IO操作次數
- 列資料具有同質性,提高資料壓縮比
- 基於列批次資料的運算,CPU的cache命中率高
執行框架
執行器是最佳化器與儲存引擎的互動樞紐。以最佳化器生成的執行計劃樹為輸入,從儲存引擎訪問資料,並按照計劃,操作各種執行運算元,從而實現資料的處理。採用Pipeline模式, 行執行器一次一tuple,列執行器一次一batch。上層驅動下層,使得資料在執行樹上流動。提供各種資料處理的執行運算元。下圖展示了自上而下的控制流和自下而上的資料流。
執行器的執行過程可分為這三個步驟:
- 執行器初始化:構造執行器全域性狀態資訊estate、遞迴遍歷計劃樹各節點,初始化其執行狀態資訊planstate
- 執行器的執行:行引擎和向量化引擎入口獨立開,從計劃樹根節點開始,遞迴遍歷到葉節點獲取一個tuple/batch,經過逐層節點運算元的處理,返回一個結果tuple/batch,直到再無tuple/batch。
- 執行器的清理:回收執行器全域性狀態資訊,清理各plan node的執行狀態。
列執行器
行執行器的問題是:CPU大部分處理在遍歷Plan Tree過程,而不是真正處理資料,CPU有效利用率低。列存表獨有的應用場景,需要配套的向量化引擎,才能真正發揮其在OLAP場景下提升效能的優勢。因此,列執行器的改造基本思路為:一次處理一列資料。
和行執行器一樣,向量化執行引擎排程器,遵循Pipeline模式,但每次處理及在運算元間傳遞資料為一次一個Batch(即1000行資料),CPU命中率提高,IO讀操作減少。列執行器的資料流結構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向量化執行引擎,對其框架、原理、各運算元概況、效能提升等做了詳細闡述。
點選關注,第一時間瞭解華為雲新鮮技術~