PG 向量化引擎

yzs87發表於2022-01-29

PG 向量化引擎

向量化引擎是 OLAP 資料庫提升效能的有效技術。翻到 PostgreSQL 郵件列表有對向量化引擎的討論。這裡進行整理,以作分析。

作者郵件

程式碼位於   ,並且合入了 PG13 中。其基本思想是擴充套件 TupleTableSlot ,引入 VectorTupleTableSlot (一個由投影列組織的列陣列)。每列的陣列在記憶體中連續。這使得表示式計算時能夠很好使用快取,並且可以使用 SIMD 。我們已經重構了 SeqScanNode AggNode ,目前支援 VectorTupleTableSlot

下面時我們設計的特點:

1) 純擴充套件。不會將任何程式碼解碼到 PG 核心中

2) CustomScan 節點。我們使用 CustomScan 框架來替換原有的執行器節點,如 SeqScan Agg 等。基於 CustomScan ,我們可以擴充套件 CustomScanState BeginCustomScan() ExecCustomScan() EndCustomScan 介面來實現向量化執行邏輯。

3) Post planner hook 。產生 Plan 後,使用 plan_tree_walker 來遍歷執行計劃樹,檢測是否可以向量化。如果可以,那麼使用向量化節點(以 CustomScan 節點的形式)替換非向量化節點(如 SeqScan Agg 等)。如果不可以,重新轉換到原始執行計劃,並使用非向量化執行器。未來會改進這一部分,例如當一些節點不能向量化時不再轉換到原始執行計劃,而是使用 Batch/UnBatch 節點來產生一個向量化和非向量化節點來相容。

4) 支援逐步實現一個新的向量化執行節點。當前僅支援向量化 SeqScan Agg ,但是開啟向量化外掛後,其他包括 Join 的查詢也可以執行。

5) 繼承原始執行器程式碼。我們選擇了一個更加平滑的方式更改當前 PG 執行器節點並將之向量化,而不是重新寫整個執行器。複製了當前執行器 node c 檔案到我們的擴充套件中,基於此新增了向量化邏輯。當 PG 改進執行器時,我們可以很方便地將之合入我們外掛。我們想了解,透過擴充套件來實現向量化執行器是否是個好方法?

6) 可拔插儲存。 PG 現在已支援可拔插儲存了。 TupleTableSlot 被重構抽象為 TupleTableSlotOps 結構。當我們將 PG 升級到最新版本時, VectorTupleTableslot 可以基於此框架完成升級。

我們執行 TPCH 10G benchmark Q1 的結果對比: PG 50s ,向量化 PG 28s 。透過以下方法效能可以得到提升:

1) heap tuple 的解碼佔用更多 CPU 資源。未來我們會使用 zedstore ,向量化執行器更適合列存。

2) 向量化 agg 並未完全向量化。我們還需要做很多最佳化。例如,批次計算 hash 值,最佳化 x 向量化 HashAgg hash

3) Datum 轉換成真實型別的代價以及反操作的代價都很高,例如 DatumGetFloat4 & Float4GetDatum 。一個最佳化方法是在 VectorTupleSlot 中直接儲存真實型別,而不是 datums 的陣列。

相關工作:

1) VOPS 也是一個向量化執行外掛:

2) Citus 向量化執行器: 。它使用 ExecutorRun_hook 來執行向量化執行器,使用 cstore fdw 來支援列儲存。

注意,現在向量化執行器基於 PG9.6 ,但是可以透過一些努力移植到 master/zedstore 。在朝著這個方向前進時,希望收到反饋,我們不勝感激。

Postgres Professional的Konstantin Knizhnik反饋及作者答覆

我認為向量化執行器對 PG 來說是絕對必要的,特別是考慮下到現在我們由列存原型 zedstore 。為了充分利用列存帶來的優勢,我們絕對需要一個向量化執行器。

但是,我不完全理解 為什麼建議將其作為擴充套件來實現 。是的。自定義節點可以在不影響 PG 核心情況下提供向量化執行。但是為了高效繼承 zedstore 和向量化執行器,我們需要擴充套件 table-AM VectorTupleTableSlot 和對應掃描函式)。當然將向量化執行器作為擴充套件更加容易,但我認為遲早應該將它新增到 PG 核心中。

據我瞭解,您已經由了一些原型實現(否則您是如何獲得效能結果的?)如果是這樣,您是否打算釋出它,或者您認為應該從頭開始開發執行器?

答覆

原型擴充套件位於 。同意某一天將向量化執行器新增到 PG 核心中。但是這麼大的特性,不僅需要改變 table-AM ,還需要改變每個執行器節點,例如 Agg,Join,Sort 節點等。以及表示式計算函式和聚合的 transition 函式、 combine 函式等。我們也需要將之向量化。因此第一步作為一個外掛來完成,如果在社群中流行並且穩定下來,我們隨時可以合入 PG 核心中。

我們確實希望從社群得到一些關於 CustomScan 的反饋。 CustomScan 只是一個抽象層。通常用於支援使用者定義的掃描節點 。但 其他一些 PG 擴充套件( pgstorm )已經將之用作通用的 CustomNode ,例如 Agg Join 等。由於向量化引擎需要在所有節點中支援向量化處理,因此遵循上述思路,我們選擇使用 CustomScan

基於 VOPS 經驗的一些擔憂:

1) 對於某些型別的查詢,向量化模型(列式)效能具有優勢,但是對於其他某些型別的查詢,他的效率較低。此外,資料以行形式匯入資料庫。一行一行插入列存非常低效。因此需要某些批次匯入工具,可以在匯入列存之前緩衝插入的資料。實際上這是資料模型的問題,而不是向量化執行器的問題。但我想在這裡表達的是, 最好同時擁有 2 中表示(水平和垂直)並讓最佳化器為特定查詢選擇最有效的一種

答覆

是的,一般來說對於 OLTP 查詢,行格式更好,而對於 OLAP 查詢,列存更好。至於儲存型別 (或資料模型),我認為 DBA 應該選擇行儲存或列儲存以用於特定表。至於執行器,讓最佳化器根據成本來進行選擇是一個好主意。這是一個長期目標,我們的擴充套件現在需要返回到原始行執行器來進行 Insert update indexScan 。我們希望我們的擴充套件可以逐步增強。

2) 列存和向量化執行器對於 select sum(x) from T where... 之類的查詢最有效。不幸的是,這種簡單的查詢在現實生活中很少使用。通常分析查詢包含 group by joint 。而且這裡的向量模型並不總是最優的(你必須從列中重建行來執行 join 和分組)。為了提高查詢執行效率,可能需要為同一資料建立多個不同投影(按屬性的不同子集排序)。

這就是為什麼 Vertica 支援投影的原因。在 VOPS 中也可以這麼做:使用 create_projection 按時,可以執行哪些屬性應該是標量,哪些可以向量化。在這種情況下,可以使用標準的 PG 執行器執行分組和 join ,同時執行向量化操作以過濾和持續聚集。

這就是為什麼 Q1 VOPS 中快 20 倍,而不是原型中的 2 倍。所以我認為列存應該可以維護表的多個投影,最佳化器應該能夠為特定查詢自動選擇其中一個。投影的同步肯定是一個挑戰問題,幸運的是, OLAP 通常不需要最新資料。

答覆

Vertica 中投影很有用,我測試過, VOPS 確實很快。如果你能夠將之貢獻給 PG 核心,那就太好了。我們的擴充套件旨在不更改任何 PG 核心程式碼、使用者 SQL 和現有表。我們將繼續最佳化我們的向量化實現:向量化 hashagg 需要實現向量化 hash 表、批次計算 hash key 、批次探測 hash 表等。當然 PG 中的原始 hash 表不是向量化 hash 表。

3) 我想知道向量化的執行器是否應該只支援內建型別和預定義的運算子?或者它應該能夠與任何使用者定義的型別、運算子、聚合一起使用?當然,支援內建標量型別要容易的多,但這與 PG 的開放性和可擴充套件性相矛盾。

答覆

是的,我們應該支援使用者定義的型別。這可以透過引入將行型別對映到向量型別的暫存器層來完成。例如 int4->vint4

4) 你有沒有想過 VectorTupleTableSlot 中儲存資料的格式?它應該是基準陣列嗎?或者我們需要以更底層格式表示向量(例如對於 rel4 型別的 float 陣列)

答覆:

我們測試結果顯示 dataum 轉換不高效,我們準備使用你提到的底層陣列格式來實現 datum 陣列。

原文


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2854552/,如需轉載,請註明出處,否則將追究法律責任。

相關文章