openGauss內(nèi)核分析(八):執(zhí)行算子探究
執(zhí)行引擎位于優(yōu)化器和存儲(chǔ)引擎之間,負(fù)責(zé)將數(shù)據(jù)從存儲(chǔ)引擎讀取出來,根據(jù)計(jì)劃將數(shù)據(jù)處理加工返回給客戶端。執(zhí)行器接收到的指令就是優(yōu)化器應(yīng)對(duì)SQL查詢而翻譯出來的關(guān)系代數(shù)運(yùn)算符所組成的執(zhí)行樹,如下圖所示:

圖中每一個(gè)方塊代表一個(gè)具體關(guān)系運(yùn)算代數(shù)符,我們稱之為算子,每個(gè)算子有統(tǒng)一的接口,從下層的一個(gè)或者多個(gè)算子獲得輸入,然后將運(yùn)算結(jié)果返回給上層算子。整個(gè)查詢執(zhí)行過程主要是兩個(gè)流,驅(qū)動(dòng)流和數(shù)據(jù)流。
向上的流代表數(shù)據(jù)流,是指下層算子將數(shù)據(jù)返回給上層算子的過程,這是一個(gè)從下至上、從葉節(jié)點(diǎn)到跟節(jié)點(diǎn)的過程。在openGauss中,所有的葉子節(jié)點(diǎn)都是表數(shù)據(jù)掃描算子,這些節(jié)點(diǎn)是所有計(jì)算的數(shù)據(jù)源頭。數(shù)據(jù)從葉子節(jié)點(diǎn),通過逐層計(jì)算,然后從根節(jié)點(diǎn)返回給用戶。
向下的流代表控制流,是指上層算子驅(qū)動(dòng)下層算子執(zhí)行的過程,這是一個(gè)從上至下、由根節(jié)點(diǎn)到葉節(jié)點(diǎn)的過程。從代碼層面來看,即上層算子會(huì)根據(jù)需要調(diào)用下層算子的函數(shù)接口,去獲取下層算子的輸入。驅(qū)動(dòng)流是從根節(jié)點(diǎn)逐層傳遞到葉子節(jié)點(diǎn)。
執(zhí)行器的整體目標(biāo)就是在每一個(gè)由優(yōu)化器構(gòu)建出來的執(zhí)行樹上,通過控制流驅(qū)動(dòng)數(shù)據(jù)流在執(zhí)行樹上高效的流動(dòng),其流動(dòng)的速度決定了執(zhí)行器的處理效率。
算子分類
關(guān)系數(shù)據(jù)庫本身是對(duì)關(guān)系集合Relation的運(yùn)算操作,執(zhí)行引擎作為運(yùn)算的控制邏輯主體也是圍繞著關(guān)系運(yùn)算來實(shí)現(xiàn)的,在傳統(tǒng)數(shù)據(jù)庫實(shí)現(xiàn)理論中,算子的分類可以分成以下幾類:
掃描算子(Scan Plan Node)
掃描節(jié)點(diǎn)負(fù)責(zé)從底層數(shù)據(jù)來源抽取數(shù)據(jù),數(shù)據(jù)來源可能是來自文件系統(tǒng),也可能來自網(wǎng)絡(luò)(分布式查詢)。一般而言掃描節(jié)點(diǎn)都位于執(zhí)行樹的葉子節(jié)點(diǎn),作為執(zhí)行樹PlanTree的數(shù)據(jù)輸入來源。
關(guān)鍵特征:輸入數(shù)據(jù)、葉子節(jié)點(diǎn)、表達(dá)式過濾

控制算子(Control Plan Node)
控制算子一般不映射代數(shù)運(yùn)算符,通常是為了執(zhí)行器完成一些特殊的流程引入的算子。
關(guān)鍵特征:用于控制數(shù)據(jù)流程

物化算子(Materialize Plan Node)
物化算子一般指算法要求,在做算子邏輯處理的時(shí)候,要求把下層的數(shù)據(jù)進(jìn)行緩存處理,因?yàn)閷?duì)于下層算子返回的數(shù)據(jù)量不可提前預(yù)知,因此需要在算法上考慮數(shù)據(jù)無法全部放置到內(nèi)存的情況。
關(guān)鍵特征:需要掃描所有數(shù)據(jù)之后才返回

連接算子(Join Plan Node)
這類算子是為了應(yīng)對(duì)數(shù)據(jù)庫中最常見的關(guān)聯(lián)操作。
關(guān)鍵特征:多個(gè)輸入。
按照實(shí)現(xiàn)方式有3種關(guān)聯(lián)算子。

按照連接類型有6種關(guān)聯(lián)算子。

下面重點(diǎn)分析Seqscan算子的代碼流程。

Seqscan?算子

ExecInitSeqScan
ExecInitSeqScan函數(shù)初始化SeqScan狀態(tài)節(jié)點(diǎn),負(fù)責(zé)節(jié)點(diǎn)狀態(tài)結(jié)構(gòu)構(gòu)造。
InitSeqNextMtd函數(shù)設(shè)定獲取元組的函數(shù)為SeqNext。
ExecSeqScan
ExecutePlan函數(shù)循環(huán)調(diào)用ExecProcNode獲取元組。
ExecProcNode函數(shù)根據(jù)nodeTag執(zhí)行g(shù)_execProcFuncTable對(duì)應(yīng)的函數(shù)。
ExecSeqScanWrap->ExecSeqScan->ExecScan->ExecScanFetch,ExecScanFetch函數(shù)回調(diào)SeqNext獲取元組。
ExecEndSeqScan
ExecEndSeqScan完成清理工作。