Mycat2 優(yōu)化器

2021-09-09 16:03 更新

前言

本文描述的設計細節(jié),大部分已經(jīng)實現(xiàn),有小部分沒有完全實現(xiàn)。

Mycat2減少使用人類理解編寫的SQL解析路由和基于經(jīng)驗制作的查詢引擎的思路來實現(xiàn)查詢引擎,取而代之,使用基于關(guān)系表達式轉(zhuǎn)換SQL的思路以支持更多甚至是標準SQL,MySQL語法的SQL。使用Java生態(tài)Apache Calcite項目,改造成以接收MySQL方言的SQL,翻譯該SQL變成Mycat算子和查詢物理庫的SQL。該引擎在設計上可以脫離網(wǎng)絡層獨立運行。

Mycat2使用calcite作為優(yōu)化器實現(xiàn),優(yōu)化有四個階段。

第一階段Mycat把MySQL語法的SQL編譯成語法抽象樹,并進一步把它編譯成邏輯關(guān)系表達式,值得注意的是,輯MySQL方言元素以Hint或者特征的形態(tài)保存在表達式內(nèi),而不會以表達式表示。

第二階段是基于規(guī)則改寫邏輯關(guān)系表達式,把可以下推到Mysql關(guān)系表達式轉(zhuǎn)換以特殊的節(jié)點保存,該節(jié)點最終執(zhí)行的時候以SQL表示運算。

第三階段是使用基于代價的優(yōu)化方法把未能下推的,需要在Mycat里運算的算子選擇物理算子。

第四階段則進一步把物理算子翻譯成對應的執(zhí)行計劃,執(zhí)行計劃是以樹節(jié)點表示的執(zhí)行樹,與執(zhí)行流程是對應的,而且是有狀態(tài)的.而上述的關(guān)系表達式是不可變對象,無狀態(tài)的。上述有微妙的關(guān)系,算子與執(zhí)行器沒有嚴格的對應關(guān)系,它們的樹形狀并不是對應的,但是有轉(zhuǎn)換程序把算子生成執(zhí)行器。

在Mycat2開發(fā)的歷史中,使用calcite實現(xiàn)的查詢引擎有兩個版本,其技術(shù)特征如下。

第一代查詢引擎

  1. 基于邏輯表結(jié)合分片條件翻譯為類似union all語義和多個物理表
  2. 在合適的條件下,上拉Union All算子,相對地,其它在Union All算子之上的算子會下推
  3. 從葉子節(jié)點開始往上遍歷(后序遍歷),計算每個節(jié)點的分片屬性,把相同分片屬性的節(jié)點的根節(jié)點記錄,然后把它向下遍歷部變成SQL。

該設計最大程度依賴calcite現(xiàn)有功能,而且下推的方法比較直觀,但是僅僅在邏輯關(guān)系表達式層面做處理,未能深入更深入的優(yōu)化,需要編寫更多規(guī)則實現(xiàn),而且對于一些情況難以控制關(guān)系表達式的改寫,另外由于開發(fā)時候?qū)儆谠缙陔A段,未能實現(xiàn)Mycat自研的執(zhí)行器所以未能使用執(zhí)行成本優(yōu)化,使用calcite的內(nèi)置執(zhí)行器實現(xiàn)執(zhí)行。它在用戶測試以及使用中發(fā)現(xiàn)使用Calcite的解釋器執(zhí)行器執(zhí)行效率較低,而代碼生成器的執(zhí)行器難以理解調(diào)試。所以開始制作第二代執(zhí)行引擎。

第二代查詢引擎

開發(fā)第二代查詢引擎的過程中,嘗試了很多方案,包括移植1.6的查詢引擎,自研SQL編譯成不支持關(guān)聯(lián)子查詢的表達式樹并自研執(zhí)行器,經(jīng)過多次方案和測試,保留自研執(zhí)行器。因為難以界定簡單sql與復雜sql,可能導致多次編譯,所以拋棄自研的SQL編譯器。為了實現(xiàn)執(zhí)行器,深入使用Calcite,實現(xiàn)MycatRel,把關(guān)系表達式轉(zhuǎn)換為Mycat自研的關(guān)系表達式類,在此之上再轉(zhuǎn)換成執(zhí)行器。執(zhí)行器保留Caclite的表達式編譯器,使用代碼生成技術(shù),對標量表達式生成java代碼,然后動態(tài)編譯成類,然后加載為對象,執(zhí)行。對于關(guān)系表達式,則是自己實現(xiàn)執(zhí)行器,而不使用代碼生成方案,雖然效率有所降低,但是便于調(diào)試,因為考慮到之后可能有替換執(zhí)行器的可能,所以暫時無需優(yōu)化至極致。

然后為了實現(xiàn)對物理節(jié)點的SQL可控,研究關(guān)系表達式與SQL的生成規(guī)則,實現(xiàn)了有效的關(guān)系表達式下推判斷器。然后為了對已排序的節(jié)點進行規(guī)則優(yōu)化,引入排序特征傳播(相比之下,手動的HBT就比較難表達這些信息了,Hint可能是一個方向)。后來再參考阿里DRDS的參數(shù)化思路,實現(xiàn)參數(shù)化功能原型.最后為了結(jié)合第一代查詢引擎的任意分配配置,基于名字而不是基于下標的分表映射方案(第二代原始設計是基于下標指向拆分的物理表),重新引入第一代查詢引擎的思路,基于規(guī)則判斷,對于復雜的SQL,邏輯表編譯成物理表再優(yōu)化。這樣就完成了第二代查詢引擎。

引入?yún)?shù)化

理想的參數(shù)化就是把sql中的直接量提取出來,用參數(shù)化標記?替代,sql就變成參數(shù)化模板,把SQL中部分常量以?替換,形成參數(shù)化模板與參數(shù)值,以該參數(shù)化模板為key,查詢緩存是否已經(jīng)有物理算子或者已經(jīng)解析好的SQL抽象語法樹,也就說緩存的對象有兩種.對于物理算子,一個參數(shù)化模板可能對應多種物理算子,這是因為使用的優(yōu)化方法不同導致的結(jié)果.Mycat會使用執(zhí)行代價的物理算子來執(zhí)行。上面說得很理想,但是還是有限制的,在Mycat2里面,暫時不會對offset,limit,以及select item的值進行參數(shù)化。前者會影響生成物理算子,因為行數(shù)對算子選擇有影響。后者會影響結(jié)果集類型的生成。

參數(shù)化的MycatView

MycatView這個名字參考阿里DRDS的View算子,在Mycat2第一代引擎有類似的東西,叫做MycatTransientSQLTableScan,一種臨時的TableScan,它以sql字符串和數(shù)據(jù)源信息來構(gòu)造。而MycatView使用關(guān)系表達式與數(shù)據(jù)分布來表示,數(shù)據(jù)分布包含兩類,一種是具體的,他們就是已經(jīng)包含具體物理表的信息。一種是需要賦以參數(shù)值才可以得到具體信息,如果不,只能得到全表掃描信息,也就是說,MycatView計算物理表可以是惰性計算的。理想情況下,一個參數(shù)化的關(guān)系表達式,不同的參數(shù)值能影響它掃描分表數(shù)量。

一對多的MycatView

一般來說,MycatView保存的關(guān)系表達式是關(guān)于邏輯表的,而物理表信息以數(shù)據(jù)分布來表示。在分表情況下,一般來說,一個邏輯表對應多個物理表。在實現(xiàn)了參數(shù)化后,關(guān)于邏輯表的關(guān)系表達式成為了模板的存在,(它也包含參數(shù)標記?)在生成執(zhí)行計劃的時候,應用參數(shù)值,使邏輯表的MycatView擴展成多個分片物理表的關(guān)系表達式。換句話說,使用MycatView‘概括’多個分片節(jié)點的關(guān)系表達式,即使用一個分片表達式與多個分片節(jié)點信息,減少規(guī)則重寫表達式存在多個重復的改寫消耗,設想,如果有100個物理表,使用邏輯表編譯成物理表的方法,如果涉及對這些物理表的關(guān)系表達式改寫則要進行100次,而使用MycatView‘概括’只需1次。

具體的MycatView

而對于復雜的sql,Mycat可能會選擇使用物理表擴展的方法來優(yōu)化,這是因為分片條件對算子的形狀影響很大,對于這個情況,mycat僅僅緩存sql抽象語法樹,并在規(guī)則優(yōu)化階段就應用參數(shù)值,把邏輯表擴展成物理表。

過早優(yōu)化的MycatView

對于簡單sql,如果在規(guī)則優(yōu)化階段已經(jīng)得到MycatView,則無需進行物理算子優(yōu)化,直接生成執(zhí)行計劃,因為MycatView本身就是物理算子。與第一代查詢引擎相比,Mycat2自研了執(zhí)行器,執(zhí)行器與物理算子存在多對一的關(guān)系,例如就算Sort節(jié)點被代價優(yōu)化器選擇為MemSort,Mycat在生成執(zhí)行器的時候發(fā)現(xiàn)帶有l(wèi)imit和排序字段會編譯成TopN執(zhí)行器,而發(fā)現(xiàn)只有l(wèi)imit時候則會僅限制行數(shù)量。

參數(shù)化與預處理語句

在一般的預處理語句,用戶提供預處理語句,預處理語句通過特殊的語法或者客戶端使用特殊通訊協(xié)議把預處理語句發(fā)送到數(shù)據(jù)庫,然后數(shù)據(jù)庫返回指向該預處理語句的句柄.當客戶端要執(zhí)行這個預處理語句的時候,通過對?賦值,然后交給數(shù)據(jù)庫執(zhí)行.預處理語句中的?是一種參數(shù)標記,一般來說,參數(shù)是直接量,它們的參數(shù)類型可以根據(jù)SQL的語法,語義推導出來出來,但是不一定完全是確定的,因為實際參數(shù)類型取決于實際值.對于整個SQL的結(jié)果集類型,是根據(jù)Select Item表達式的類型推導出來的.如此來說,整個結(jié)果集的類型實際上也是不確定的.

外部參數(shù)化

對于客戶端相關(guān)的預處理語句參數(shù),在Mycat的查詢引擎中稱為外部參數(shù),它們就是直接量.對于把沒有?參數(shù)化標記的SQL轉(zhuǎn)換成帶有?和參數(shù)值的SQL對象,這個過程稱為參數(shù)化.在這里我們把外部參數(shù)相關(guān)的參數(shù)化叫做外部參數(shù)化。

內(nèi)部參數(shù)化

在SQL層面上,不同的SQL產(chǎn)生的邏輯關(guān)系表達式可能是相似的.把TableScan,Values的算子去掉,它們是相同的。如果把關(guān)系表達式也用?來表示,則稱為內(nèi)部參數(shù)化,如果以SQL模板來表示內(nèi)部化參數(shù)則表名也是?。這樣的SQL模板更為通用。Mycat暫時沒有顯式實現(xiàn)這種方式但有使用這種思路。

不參數(shù)化的直接量

  1. 對物理算子的形態(tài)有很大影響的,比如limit的參數(shù),而且limit的參數(shù)可以計算結(jié)果集的行數(shù),會影響物理算子的選擇,所以此類的參數(shù)化止步于物理算子生成之前。
  2. 表名(實際上不能當做直接量),Mycat2沒有進一步把表名用參數(shù)化標記表示,而保留邏輯表來表示表信息,當生成執(zhí)行器的時候,邏輯表信息會被替換成物理表
  3. and/or/in表達式,Mycat2也沒有把and/or的條件中的直接量以數(shù)組的形式排列,而選擇保持原樣。
  4. select item中的直接量

關(guān)聯(lián)子查詢

Calcite在編譯SQL的時候會解子查詢,使用join,SemiJoin,Agg替代關(guān)聯(lián)子查詢,最后還有小部分子查詢不能消去,以Correlate的形式存在,對于這個算子,Mycat2的執(zhí)行器暫時不支持(如果以后這種sql確實有很多需求就考慮支持)。涉及到Correlate的關(guān)系表達式,要求它的執(zhí)行器的輸入直接具備引用外部上下文變量的功能,具體就是表達式編譯的時候,生成的表達式要求支持變量來自其所在的關(guān)系表達式之上的Correlate節(jié)點。

內(nèi)置表

Mycat2支持自定義表數(shù)據(jù)的來源,具體要自定義開發(fā)。暫時能確定的下推的接口是Filter,Project,Limit,Sort。而對于元表相關(guān)的,暫時沒有實現(xiàn)下推接口的計劃。

RBO(基于規(guī)則的優(yōu)化)

SQL經(jīng)過解析轉(zhuǎn)換成抽象語法樹,然后進行語法級別的規(guī)范化(基于SQL改寫,化簡一些稍復雜表達式到統(tǒng)一語法),然后基于語法節(jié)點推導對應的值類型.并驗證類型轉(zhuǎn)換,最后轉(zhuǎn)換成關(guān)系表達式。然后關(guān)系表達式進行優(yōu)化階段。Mycat2首先進行RBO,使用自定義的規(guī)則,對關(guān)系表達式進行優(yōu)化。RBO的實現(xiàn)各式各樣,在Mycat2的RBO實現(xiàn)中,使用基于Calcite的Hep優(yōu)化器,它對規(guī)則依次應用,直到關(guān)系表達式不再變化,即優(yōu)化結(jié)束。另一方面,Mycat2也有直接使用前序遍歷結(jié)合后序遍歷關(guān)系表達式樹直接進行改寫的實現(xiàn)方式,但是最后還是把這種實現(xiàn)方式直接‘嵌入’到Hep優(yōu)化器之內(nèi)進行。這樣實現(xiàn)的好處是,1.可以利用Hep優(yōu)化器的驗證校驗節(jié)點類型的功能,檢查錯誤。2.統(tǒng)一優(yōu)化規(guī)則的實現(xiàn)方式,即統(tǒng)一使用Calcite的框架實現(xiàn),因此規(guī)則使用上不區(qū)分Hep優(yōu)化器還是volcano優(yōu)化器。但是也會導致一些問題,RBO在優(yōu)化器遇上矛盾的規(guī)則的時候,可能會導致規(guī)則之間相互優(yōu)化,導致不能停機(到達優(yōu)化限制次數(shù))。最后,Mycat不把RBO的規(guī)則完全放在CBO中,是為了減少CBO中搜索的優(yōu)化空間過大,Mycat2主要使用場景是TP場景,對響應及時性要求很高,而優(yōu)化關(guān)系表達式是需要耗費不確定的時間,為了減少優(yōu)化時間,所以存在RBO優(yōu)化階段。

總體來說,通過RBO應用一部分邏輯關(guān)系表達式優(yōu)化的規(guī)則,然后CBO再應用物理算子規(guī)則。

CBO(基于成本的優(yōu)化)

Mycat2的CBO主要是完成邏輯關(guān)系表達式,選擇物理算子,轉(zhuǎn)換到物理算子的任務。Mycat2在TP場景的設計上,CBO并沒有改寫關(guān)系表達式樹的形態(tài),僅僅是邏輯關(guān)系表達式到物理關(guān)系表達式的一對一映射。CBO通過獲得葉子節(jié)點(數(shù)據(jù)源)的信息,一般是指行數(shù),然后根據(jù)窮舉使用物理算子的計算代價規(guī)則,生成每個算子的執(zhí)行代價(一般是行數(shù),cpu代價,內(nèi)存代價),以及物理算子之間的要求,比如一些算子對后置節(jié)點具有排序要求。綜合這些信息,使用動態(tài)規(guī)劃算法,最后組裝出使用物理算子表達的關(guān)系表達式。CBO需要統(tǒng)計組件支持。

生成執(zhí)行器

在生成執(zhí)行器的階段,要求關(guān)系表達式具有完全的信息,例如,參數(shù)化之后關(guān)系表達式,不提供其參數(shù)值,這肯定是不能執(zhí)行的。生成器根據(jù)參數(shù)值以及必要的上下文,把還沒有確定具體分片的View轉(zhuǎn)換成具體的View,并收集涉及參與使用數(shù)據(jù)源。最后還適配不同的執(zhí)行工具,比如proxy的,只支持獲取單一數(shù)據(jù)源的實現(xiàn)。jdbc的,涉及多個分片的。

第二代查詢引擎執(zhí)行流程

  1. SQL解析成語法抽象樹->轉(zhuǎn)換成邏輯關(guān)系表達式
  2. 檢查SQL特征,選擇優(yōu)化方式
    1. 優(yōu)化方式1 下推Filter 結(jié)合Filter與邏輯表擴展成物理表 上拉Union All語義
    2. 優(yōu)化方式2 下推Filter條件同時生成MycatView
  3. 選擇物理算子
  4. 生成執(zhí)行器并執(zhí)行

由于Mysql本身對于一些語法執(zhí)行效率不高,Mycat在第一代查詢引擎與第二代查詢引擎都有選擇性地(不下推)下推集合操作來減少Mysql執(zhí)行這些sql的效率低下。在第一代查詢引擎中,從葉子節(jié)點開始后序遍歷,記錄相同分片目標的節(jié)點,然后再次后序遍歷,直到遇上不滿足下推條件的節(jié)點,然后把它的子節(jié)點翻譯成SQL。

相似地,在第二代查詢引擎中也有類似邏輯,但是不像第一代引擎是有獨立的翻譯階段,而是與其他RBO規(guī)則一起在相同的優(yōu)化器里進行規(guī)則轉(zhuǎn)換,,同時轉(zhuǎn)換時候可以傳播排序信息,如果遇上能轉(zhuǎn)換為MegreSort的條件,就會馬上轉(zhuǎn)換,而無需在CBO階段中完成.若果MycatView階段在RBO階段已經(jīng)被提升到根節(jié)點,那也無需進行CBO了.當RBO完成的時候,根節(jié)點不是物理算子,會進行CRO進一步轉(zhuǎn)換成物理算子(第一代查詢引擎沒有這個階段),通過計算節(jié)點特征和行數(shù)等統(tǒng)計信息來選擇物理計劃。

MycatView的生成規(guī)則

設計目標是盡量生成簡單的SQL,同時讓后端數(shù)據(jù)庫(Mysql)執(zhí)行一定量的運算,總體來說,算子應該區(qū)分二階段

以MycatView為邊界,MycatView之上的算子為Mycat2執(zhí)行的算子,MycatView之下為MySQL要執(zhí)行的運算.MycatView之上的算子能否下推到MycatView之下,一般來說有兩個規(guī)則

  1. 如果MycatView之上的節(jié)點放在MycatView之下的節(jié)點的根節(jié)點之上,是否會導致整體算子運算執(zhí)行效率降低,尤其是MySQL上的執(zhí)行.
  2. MycatView之下的算子的類型集合是否已經(jīng)包含MycatView之上的算子類型,如果不存在,則一般可以下推,否則參考下一條規(guī)則
  3. MycatView之下的算子從葉子節(jié)點向根節(jié)點遍歷所得的關(guān)系表達式的順序是否是自然的,這條規(guī)則的另一種表達是,MycatView之下的關(guān)系表達式對應的SQL無需以子查詢來表達,特殊情況如下
  4. 對于部分能通過SQL表達的簡化關(guān)聯(lián)子查詢在Mycat中執(zhí)行的下推,直接下推到MycatView
  5. 對于join 全局表,直接下推到MycatView

RBO規(guī)則化轉(zhuǎn)換

基于兩個節(jié)點的下推判斷,?指任意關(guān)系表達式

TableScan

TableScan=>MycatView(TableScan)

Filter

Filter(MycatView(Project(?)))≠>
Filter(MycatView(Set(?)))≠>
Filter(MycatView(Agg(?)))=>MycatView(Filter(Agg(?)):group by having語法
Filter(MycatView(Sort(?)))≠>
Filter(MycatView(Filter(?)))≠>MycatView(Filter(?)):需要MycatView之上合拼Filter
Filter(MycatView(Join(?)))=>MycatView(Filter(Join(?)))
Filter(MycatView(TableScan(?)))=>MycatView(Filter(TableScan(?)))

Project

Project(MycatView(Project(?)))=>MycatView(Project(Project(?)):盡量合拼Project
Project(MycatView(Set(?)))≠>
Project(MycatView(Agg(?)))=>MycatView(Project(Agg(?))
Project(MycatView(Sort(?)))≠>
Project(MycatView(Filter(?)))=>MycatView(Project(Filter(?)))
Project(MycatView(Join(?)))=>MycatView(Project(Join(?)))
Project(MycatView(TableScan(?)))=>MycatView(Project(TableScan(?)))

Join

Join(MycatView(Project(?)))≠>
Join(MycatView(Set(?)))≠>
Join(MycatView(Agg(?)))≠>
Join(MycatView(Sort(?)))≠>
Join(MycatView(Filter(?)))≠>
Join(MycatView(Join(?)))=>MycatView(Join(Join(?)))
Join(MycatView(TableScan(?)))=>MycatView(Join(TableScan(?)))

Agg

Agg(MycatView(Project(?)))=>MycatView(Agg(Project(?)))
Agg(MycatView(Set(?)))≠>
Agg(MycatView(Agg(?)))≠>
Agg(MycatView(Sort(?)))≠>
Agg(MycatView(Filter(?)))=>MycatView(Agg(Filter(?)))
Agg(MycatView(Join(?)))=>MycatView(Agg(Join(?)))
Agg(MycatView(TableScan(?)))=>MycatView(Agg(TableScan(?)))

Sort

Sort(MycatView(Project(?)))=>MycatView(Sort(Project(?)))
Sort(MycatView(Set(?)))≠>
Sort(MycatView(Agg(?)))=>MycatView(Sort(Agg(?)))
Sort(MycatView(Sort(?)))≠>
Sort(MycatView(Filter(?)))=>MycatView(Sort(Filter(?)))
Sort(MycatView(Join(?)))=>MycatView(Sort(Join(?)))
Sort(MycatView(TableScan(?)))=>MycatView(Sort(TableScan))

Set

Set(MycatView(Project(?)))≠>
Set(MycatView(Set(?)))≠>
Set(MycatView(Agg(?)))≠>
Set(MycatView(Sort(?)))≠>
Set(MycatView(Filter(?)))≠>
Set(MycatView(Join(?)))≠>
Set(MycatView(TableScan(?)))=>MycatView(Set(TableScan))

Correlate

Correlate(MycatView(Project(?)))≠>
Correlate(MycatView(Set(?)))≠>
Correlate(MycatView(Agg(?)))≠>
Correlate(MycatView(Sort(?)))≠>
Correlate(MycatView(Filter(?)))≠>
Correlate(MycatView(Join(?)))≠>
Correlate(MycatView(TableScan(?)))=>MycatView(Correlate(TableScan))

Mycat物理算子

HBT執(zhí)行也是使用這套物理算子

MycatProject

  1. 執(zhí)行投影操作
  2. 執(zhí)行表達式計算
  3. 流式

MycatFilter

  1. 執(zhí)行過濾操作
  2. 流式

MycatNestedLoopJoin

  1. 當其他join實現(xiàn)無法被選擇的時候使用
  2. 左側(cè)源流式,右側(cè)數(shù)據(jù)源支持可重復計算或者使用臨時表緩存計算結(jié)果
  3. 兩重循環(huán)計算

MycatNestedLoopSemipJoin

SemiJoin版本的NestedLoopSemipJoin

MycatHashJoin

  1. 用于等值連接的Join
  2. 左側(cè)源流式,右側(cè)拉取所有數(shù)據(jù)

MycatSemiHashJoin

SemiJoin版本的MycatHashJoin

MycatBatchNestedLoopJoin(一般關(guān)閉,因為優(yōu)化器暫時沒有根據(jù)左側(cè)數(shù)據(jù)源得到行統(tǒng)計)

  1. 用于左側(cè)數(shù)據(jù)源的結(jié)果數(shù)量較少的情況,右側(cè)是MycatView關(guān)系表達式,Join有顯式的關(guān)聯(lián)鍵
  2. 左側(cè)源流式,右側(cè)源需要是MycatView(轉(zhuǎn)換成LookupExecutor),此MycatView在JDBC數(shù)據(jù)源可以重復從左側(cè)源得到參數(shù)值應用并生成SQL執(zhí)行,支持涉及多個分片。

MycatSortMergeJoin

  1. Join有顯式的等價關(guān)聯(lián)鍵,并且是inner join.此時Join的兩個源的已經(jīng)按照Join key排序,則應用MycatSortMergeJoin規(guī)則
  2. 兩側(cè)源流式處理
  3. 輸出結(jié)果已排序

MycatMergeSemiJoin

SemiJoin版本的MycatHashJoin

MycatHashAgg

  1. 當其他Agg實現(xiàn)無法被選擇的時候使用

MycatSortAgg

  1. 當源已對需要聚合的字段排序,則使用MycatSortAgg替代MycatHashAgg

MycatMemSort

  1. 在當無法使用其他排序算子的時候使用
  2. 當只有排序字段的時候,而沒有offset,limit的時候,在生成執(zhí)行器時候會把數(shù)據(jù)保存到內(nèi)存然后再排序
  3. 當只有offset,limit的時候,會進行流式計算偏移與行數(shù)等價于MycatLimit算子
  4. 當同時有排序字段,offset,limit的時候,等價于MycatTopN算子,在生成執(zhí)行器的時候使用TopN執(zhí)行器

MycatTopN

  1. 當邏輯關(guān)系表達式具有排序字段,offset,limit的時候,應用MycatTopN算子
  2. 固定內(nèi)存占用空間

MycatMegreSort

  1. 當MycatView是已經(jīng)排序的時候,而且MycatView內(nèi)的算子是設計多個分片的,則使用MycatMegreSort合拼這些分片的數(shù)據(jù)
  2. 強制使用MycatSortMergeJoin或者MycatSortAgg需要添加Sort算子,則該sort算子會被轉(zhuǎn)換為MycatMegreSort
  3. 當出現(xiàn)Sort(UnionAll(Sort(...),Sort(...)))都對相同的字段排序的時候,會轉(zhuǎn)換成MycatMegreSort(UnionAll(Sort(...),Sort(...)))

MycatUnion

  1. union all的時候,使用流式合拼,對數(shù)據(jù)源依次求值 2, union distinct的時候使用集合語義,把數(shù)據(jù)拉取到內(nèi)存里運算

MycatMinus

  1. 求差,使用集合語義,把數(shù)據(jù)拉取到內(nèi)存里面運算,mysql語法不支持這個算子,HBT使用

MycatIntersect

  1. 求交集,使用集合語義,把數(shù)據(jù)拉取到內(nèi)存里面運算,mysql語法不支持這個算子,HBT使用

MycatValues

  1. 針對邏輯關(guān)系表達式中產(chǎn)生的小型臨時表,or/in表達式產(chǎn)生的臨時表,集合運算產(chǎn)生的臨時表使用MycatValues表示,其中HBT也用到了該算子
  2. MycatValues等價與沒有表信息的表,具有字段信息和在內(nèi)存存放的行數(shù)據(jù)(字面量)

MycatInsert

  1. 分表表專用插入算子,把sql參數(shù)化之后得出sql模板,與相應的表信息
  2. MycatInsert在生成執(zhí)行器的時候應用參數(shù)值,并計算分片節(jié)點信息,改寫sql模板,替換邏輯表為物理表,對同一個分片,同一個分片表的sql分組,得到對應的參數(shù)值組,然后就是使用jdbc api進行預處理的批量插入.批量插入的sql一般會生成兩種 對于values(xxx,xxx,xxx),(xxx,xxx,xxx)語法中都是字面量的時候,Mycat2會把它們參數(shù)化,得到values(?,?,?)和兩組參數(shù)值. 而對于values中使用表達式的情況,比如values(1+1,1),(2,2)這個情況,參數(shù)化結(jié)果是values(?+?,?),(?,?)和一組參數(shù)值, 當生成執(zhí)行器,參數(shù)應用的時候,會先應用參數(shù)值然后把values(?+?,?),(?,?)拆分成兩組values(?+?,?)與(?,?),計算分片節(jié)點,然后再使用jdbc插入
  3. 如果MycatInsert僅僅涉及一個分片的時候,同時Mycat2當前的事務模式是proxy的,就會把sql模板與參數(shù)值結(jié)合生成最終的sql,然后使用proxy api執(zhí)行.
  4. 對于涉及到全局序列號的生成,mycat會修改sql模板,如果插入的字段沒有自增序列,則sql模板補充自增字段.序列號的值作為預處理語句的參數(shù)值.

MycatUpdate

  1. 對于普通表,全局表的update,delete,insert,使用該算子表達
  2. 對于分片表的update,delete也是使用該算子表達
  3. 該算子把sql參數(shù)化,得到sql模板,和待求值的分片信息,當生成執(zhí)行器的時候,應用參數(shù)值,得到對應的分片范圍,然后使用物理表替換sql模板中的邏輯表,然后使用jdbc預處理語句進行執(zhí)行
  4. 與MycatInsert相同,如果處于proxy模式,則嘗試使用proxy模式執(zhí)行
  5. 該算子與MycatInsert的不同點是MycatUpdate的生成的變化點在于分片信息,具體是根據(jù)分片信息修改sql的表名,而其他部分無需多加處理,而MycatInsert則復雜得多.
  6. 與MycatInsert都是針對分庫分表設計的算子,最終執(zhí)行的形態(tài)都是sql

MycatTableModify

  1. 該算子暫未啟用,用于表示對查詢結(jié)果的行數(shù)據(jù)修改應用到涉及的物理表上的運算
  2. 涉及的物理表要求配置主鍵信息
  3. 該算子也準備用于表達內(nèi)置表的修改

MycatView

  1. MycatView劃分Mycat運算的算子與數(shù)據(jù)庫運算的算子(物理節(jié)點算子)
  2. MycatView使用邏輯表的邏輯關(guān)系表達式與分片具體值無關(guān)的數(shù)據(jù)分布信息表示,要么是全表信息,要么是參數(shù)化的分布信息,要么是具體的分布信息.對于參數(shù)化的分布信息,在真正求值的時候,也就是應用參數(shù)值的時候才產(chǎn)生具體的分布信息.如果無法找不到有效的分片條件的時候,就會使用全表信息,全表信息也是具體的分布信息.特殊地對于物理表, 分布信息肯定是具體的,分片信息就是一個分片的,而且關(guān)系表達式就是物理表相關(guān)的,不包含邏輯表.
  3. 與之相對的是MycatTransientSQLTableScan
  4. 當MycatView之下涉及多個分片的時候,生成執(zhí)行器可能就帶有并行拉取這些分片數(shù)據(jù)的特性,而無需顯示的Gather算子指定并行

MycatTransientSQLTableScan

  1. 使用sql與分片目標表達的數(shù)據(jù)源算子,與MycatView不同的是,MycatTransientSQLTableScan就是具體的sql字符串
  2. 沒有關(guān)系表達式,而且就是一對一的,一個分片目標與一個sql.而MycatView之下可能還涉及多個分片目標,但是只有一個關(guān)系表達式

建立臨時表

有一些要求輸入的數(shù)據(jù)源支持重復計算(迭代,rewind)的執(zhí)行器,Mycat2在不支持重復迭代的輸入源的執(zhí)行器會加上一個保存行數(shù)據(jù)的包裝器,這個包裝器會保存輸入的執(zhí)行器的數(shù)據(jù),這樣就可以得到支持重復迭代的執(zhí)行器。

一代與二代的配置不同

在第一代查詢引擎中,全局表配置是任意的,而沒有關(guān)于普通表的配置.這種設計的原因是配置一個單分片信息的全局表就具備普通表的功能.當分片表join全局表的時候,union的上推和分片sql的計算能把全局表與join的物理表join,然后合拼,并把相同分片節(jié)點的關(guān)系表達式變成sql.

而在第二代查詢引擎中,使用自定義的sql生成規(guī)則,對于全局表的語義,在join總是兩個子關(guān)系表達式式,多個join的時候總是以二叉樹的形態(tài)存在的時候,涉及全局表的join總是能下推的,如果全局表的schema與table名字不一樣,那么還需要計算對應的物理表是哪個.這樣略顯復雜,冗余,所以規(guī)定在第二代查詢引擎,全局表總是要存在所有分片,而且?guī)烀砻家恢?包括邏輯表.而對于普通表,如果采用MycatView的方法,即使是同一個分片的下推也是要計算對應的物理表。

全局表,普通表,分片表

在第二代查詢引擎中,要求全局表,普通表的物理庫名字,物理表名字分別與邏輯庫名字,邏輯表名字一致.

這樣的設計的好處是,mycat對于非用戶關(guān)心的sql,比如show語句,無需進行sql改寫表名,直接發(fā)到對應的物數(shù)據(jù)源上就可以了.更進一步的設計是指定一個物理數(shù)據(jù)源專門處理這些sql.而第一代查詢引擎涉及到了sql改寫,稍微復雜.

另外一個方面,全局表要求每個數(shù)據(jù)源上都有對應的物理表,而不像1代中,可以任意配置.這是為了與ER表下推全局表做簡化處理,如果簡化下推全局表的檢查過程.對于普通表,只需檢查sql的涉及的表信息,只有普通表的時候,直接把原sql發(fā)到數(shù)據(jù)源上即可,更一步的設計是固定一個數(shù)據(jù)源,對于普通表,或者沒有配置的表的sql,直接發(fā)到此節(jié)點.普通表與沒有配置的表的區(qū)別是前者顯式制定了他們會參與分片路由,而后者,一般來說,只是進行讀寫分離處理.對于分片表,分析出是sql中只有一個表,而且分析得出的分片算法。

對于分片表,物理庫與物理表的名字一般具有規(guī)律,有規(guī)律的名字容易與分片規(guī)則結(jié)合,生成物理表信息.無論在第一代查詢引擎與第二代查詢引擎中,都有明確指定配置分片信息設計傾向.主要原因是有些用戶分庫分表,有些是先分庫,此時他們的物理表,名字是相同的,有些用戶是先分表,他們的名字并不相同,還有一些用戶一開始就是分庫分表,然后選擇分庫來擴展性能.加上有些用戶的系統(tǒng)是已經(jīng)有分片的設計,后來再使用Mycat做分庫分表,有自己的表名規(guī)則.情況比較復雜,所以mycat在配置分片表,一般要求配置所有的存儲節(jié)點。

關(guān)于分片算法

  1. 分片算法是根據(jù)分片條件計算出分片信息的對象,而分片信息一般就是指向數(shù)據(jù)源,物理庫,物理表信息的對象,Mycat會使用此信息對sql進行改寫,一般來說一個分片信息只涉及一個表信息,結(jié)合上述的ER表下推,就可以理解這個涉及多表下推的復雜。
  2. 配置文件中dataNodes是供分片算法提供全表掃描的信息,而分片算法可以根據(jù)實際情況,比如根據(jù)分片值得出物理庫,物理表名.當在條件中找不到分片值的時候,使用全表掃描.Mycat2的分片算法的接口接收完整的條件表達式,用戶可以根據(jù)實際情況寫分片算法實現(xiàn)計算分片。

關(guān)于DataNode

Mycat2總體設計上模糊了在1.6中dataNode的概念,并不明確.在1.6中,dataNode數(shù)據(jù)源和物理庫名為固定信息,而要求表名在路由中改寫(Mycat先去掉sql中的庫名.分庫不改寫表名,分表改寫表名),往大一點的方向來說,這個dataNode強調(diào)了節(jié)點這個概念,而固定物理庫名實際上是路由的改寫要求,.而在2.0中一個dataNode在配置中體現(xiàn)就是表分片(以后考慮配置中把dataNode更名,減少混亂).即其中一個分表,無論他是在一個數(shù)據(jù)源上還是在不同的物理庫.在Mycat2的早期sql生成機制中,如果只涉及一個數(shù)據(jù)源的sql,就使用union all合拼sql,也就是說,無論跨庫還是跨表,總能把查詢邏輯表的sql翻譯成查詢多個物理表的一條sql.但是由于mysql的執(zhí)行機制問題,性能并沒有顯著提高.所以Mycat2顯著的設計是默認對于涉及多個物理表的查詢,優(yōu)先并行拉取多個數(shù)據(jù)源的數(shù)據(jù),而使用union all合拼同一個數(shù)據(jù)源的結(jié)果集則是次要考慮。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號