openLooKeng執行計劃優化簡介
在講述下推框架以前,咱們先來簡單介紹一下openLooKeng執行計劃優化的大體流程。node
如上圖所示,接收到用戶SQL語句以後,SQL被轉換成一個Abstract syntax tree (AST)樹。AST樹再被轉換成邏輯執行計劃樹。而後,也就是執行計劃優化過程當中最重要的一步,使用規則(Rule)或者優化器(Optimizers)進行執行計劃優化,每個PlanOptimizer能夠操做一個子執行計劃樹,PlanOptimizer基於統計或者經驗,用一個更優的子執行計劃替換當前的子樹,達到優化的目的。PlanOptimizers一般是長期的經驗累積得出來的一些優化規則,好比謂詞下推、join reorder等等。PlanOptimizers能夠存儲一些物理執行信息在ConnectorHandle中。新下推框架則工做在這一層。mysql
獲得最優的執行計劃以後,邏輯執行計劃被轉換成物理執行計劃,而後被分片,分割成按照stage執行的一個個子樹,最終調度到worker上執行。git
PrestoSql下推方案介紹
最初,openLooKeng是從PrestoSql演進而來,在其基礎上增長了不少功能特性,以及大量的性能優化。在講述openLooKeng的新下推框架以前,先大概介紹其原下推方案。sql
- 根據社區的討論,PrestoSql原下推框架有一些目標:
1)使用現有的Rule或Optimizer的框架,並且不是使用基於visitor模式的PlanOptimizers來實現下推,同時可以讓connector提供轉換rules來實現下推;數據庫
2)並非創建一個原生的機制來支持全部操做的下推。性能優化
- 先來看看prestoSql的執行過程:
1)首先,引入一些列的下推規則,每個規則負責下推相應的操做到TableScan操做中,好比PushFilterIntoConnector, PushProjectionIntoConnector, PushAggregationIntoConnector等等;數據結構
2)上述的這些rules經過指定的metadata調用與connectors交互,若是connector支持這個操做下推,操做則被下推到TableScan操做,同時在connectorTableHadle中記錄相關信息。框架
- 下面以PushFilterIntoConnector爲例說明。
在上述的例子中,假設filter中有兩個過濾條件,一個是like,一個是f函數,其中connector能處理like表達式。ide
PushFilterIntoConnector會調用 Metadata.pushFilter,其實是調用connector的pushFilter函數,這個函數會返回一個新的tableHandle,新的tableHandle中記錄了like表達式的相關信息,同時返回一個remaining filter,即connector不能處理的表達式。最終,PushFilterIntoConnector就把原來的執行計劃(上圖中第一個框)轉換成一個新的執行計劃(上圖中最後一個框)。函數
- 上述的基於Rule的下推方案存在如下的幾個問題:
1)不能JoinNode,WindowNode等Nodes的下推,特別是 join的狀況,join node不只僅須要visit當前的join node,還須要visit他的左右節點,同時,還須要保存join的上下文信息,基於rule的下推方案難以處理這種狀況;
2)下推邏輯複雜,下推上下文信息沒法保存,對於Join的狀況,join的下推信息不知道存儲在哪。
3) 基於上述緣由,當前的下推方案不能把sql語句下推到數據源操做中,這樣對於那些執行速度至關快的數據源就不能充分發揮數據源自己的能力,因此引入了新的下推框架。
openLooKeng新的下推框架
- 思想
openLooKeng新下推框架的主要思想是把執行計劃子樹暴露給connector,讓connector提供PlanOptimizers(基於visitor模式的)給執行優化引擎,這樣可讓connector引入任意的優化。
爲了防止一個connector的PlanOptimizers修改其餘connector的執行計劃子樹,openLooKeng對於暴露給Connector的PlanNode作了兩個限制:
1)暴露出來的PlanNodes須移動到presto-spi模塊;
2)僅僅暴露屬於connector的子執行計劃樹給相應的connector。以下圖所示,左子樹只會暴露給Hive Connector,右子樹只會暴露給Mysql Connector。而後會應用他們各自的PlanOptimizers。
- 實現
openLooKeng的下推框架如上圖所示,新下推框架的工做原理很簡單,主要分爲兩步:
1)Connector在啓動的時候會告訴執行優化引擎其提供的ConnectorPlanOptimizer,以下圖的HiveFpuPushdownOptimizer,其須要實現上圖的optimize接口,optimize函數以子執行計劃爲入口,返回優化後的執行計劃;
2)在執行優化引擎中引入ApplyConnectorOptimization優化器,
該Optimizer會把根據子執行計劃所在的connector,調用其connectorPlanOptimizer。以下圖所示,通過HiveFpuPushdownOptimizer優化以後,Aggregation和Filter操做都下推到了數據源中。
- 修改
新框架特性PR連接爲
https://gitee.com/openlookeng/hetu-core/pulls/633,
主要作了以下修改:
-
移動PlanNodes到presto-spi模塊
-
修改PlanNode和Assignments中的Expression爲RowExpression(下一節描述)
-
添加TranslateExpressions 和 ApplyConnectorOptimization Optimizer
-
修改已經存在的Rules和Optimizers
-
爲connector添加ConnectorPlanOptimizer
- Expression-to-RowExpression
在數據庫或者查詢系統中,爲了更好的隔離,AST樹和IR樹是隔離,他們使用的數據結構也不同,這也就是presto社區討論的分離AST(Node)和IR(PlanNode)。具體就是指把AST樹種的Expression轉換成PlanNode中的RowExpression。當前AST和PlanNode在混用Expression,不能作到很好的隔離。rker上執行。
當前一個執行計劃的生命週期以下:
building AST
building raw plan
plan optimization
plan sanity check
plan cost computation
building subplans
distributing subplan (over the wire)
compiling subplan locally
當前,Expression到RowExpression的轉換髮生在第8步。咱們把轉換這個操做移到了第3步。之因此沒有把沒有把轉換移到第二步,是由於涉及的面太廣了,修改量太大了。
Example 演示
首先,在演示系統中配置了三個catalog,他們都指向同一個數據源,不過下推的設置不同,mysql2不下推,mysql1部分下推(join不下推),mysql全下推。
不下推的狀況
部分下推的狀況,在這個例子中,filter下推了
所有下推狀況
如何貢獻
下面簡單介紹一下開發者如何適配新的下推框架,即在新增的connector中,如何添加connectorPlanOptimizer。主要步驟以下:
第一:在XXXConnector中複寫下面的函數
第二:實現XXXPlanOptimizerProvider
第三:在XXXConnector中實現PlanOptimizer
第四:實現PlanOptimizer裏面的optimize函數,主要是實現一個visitor去visit執行計劃樹
第五:實現Visitor,用來生成下推的語句,同時修改執行計劃樹
第六:實現XXXQueryGenerator,在XXXQueryGenerator中實現一個visitor用來把下推的信息記錄到XXXQueryGeneratorContext,若是存在節點能夠下推,則生成對應的sql
詳細的實現能夠參考openLooKeng的baseJdbc的實現,實現了JDBC數據源的下推。
以上即是openLooKeng開發工程師羅旦帶來的分享。
直播視頻回顧:https://www.bilibili.com/video/BV1of4y1p7sc
活動官網:https://summer.iscas.ac.cn/
學生指南:https://summer.iscas.ac.cn/help/student/
任務詳情:https://summer.iscas.ac.cn/#/org/orgdetail/openlookeng
openLooKeng是一款開源的高性能數據虛擬化引擎,提供統一SQL接口,具有跨數據源/數據中心分析能力,爲大數據用戶提供極簡的數據分析體驗。
openLooKeng開源社區官方網站: https://openlookeng.io/zh-cn/
openLooKeng代碼倉地址: http://gitee.com/openlookeng