作者:的個人主頁
原始碼分析:
ExecutorStart 部分代碼主要需要的資料結構有:QueryDesc:查詢描述符,實際是需要執行的SQL陳述句的相關資訊,包含由CreateQueryDesc函式設定的操作型別、規劃器的輸出計劃樹、元組輸出的接收器、查詢環境變數以及由ExecutorStart函式設定的結果元組tuples描述、執行器狀態、和per-plan-node狀態樹,具體結構見后面的執行器的主要資料結構分析 CmdType:由 Query 或 PlannedStmt 表示的操作型別的列舉;包括CMD_SELECT、CMD_UPDATE, CMD_INSERT, CMD_DELETE, CMD_MERGE,等
PlanState :PlanState是所有PlanState-type節點的虛父類,從未被實體化另外一個傳入 Executor 的引數是 eflag,它的定義在 executor.h 中

除錯程序如下:

2、向下執行,發現此時 hook 上掛載了 explain_ExecutorStart 函式,于是進入開始執行函式,該函式負責檢查是否需要啟動審計功能,
函式,分別進入如下幾個函式,進行了一些操作,</p>
<p>(1)estate = CreateExecutorState();</p>
<p><img src=)
創建并初始化一個EState節點,它是用于整個Executor呼叫的作業存盤,*主要地,這將創建每查詢記憶體背景關系用于保存直到查詢結束為止的所有作業資料,
注意,每查詢背景關系將成為呼叫者的子背景關系
(2)ExecAssignExprContext,
(4) execopenscanrelation打開堆關系被掃描一個基本級別的掃描計劃節點,*這應該在節點的ExecInit例程中呼叫,
默認情況下,獲取關聯的AccessShareLock,但是,如果關系已經被InitPlan鎖定,我們就不需要獲得任何額外的鎖定,這節省了到共享鎖管理器的訪問, 2、之后函式呼叫 exec_explain_plan()對 queryDesc 進行決議3、決議成功后檢查是否存在 ExecutorRun_hook, 如果 不存在則執行標準 ExecutorRun,這里同樣已經被掛載了 explain_ExecutorRun() <o:p></o:p> 正如注釋所說,該函式負責跟蹤嵌套深度,一旦深度超出限制,則拋出一個例外, 4、執行完成這部分后,進入到standard_ExecutorRun(queryDesc, direction, count);函式中呼叫了CreateExprContext函式,在EState中為運算式計算創建背景關系, 5、hook 上被掛載了函式 hypo_executorEnd_hook 它的作用是重置 isExplain 標志,此時查詢已經執行完了,所以對標志進行重置,為下一輪查詢做好作業,6、進入standard_ExecutorEnd;相關函式有:(1)ExecFreeExprContex計劃節點的ExprContext應該在執行器關閉期間被顯式釋放,因為可能有需要呼叫的關倍訓呼,(上述例程生成的其他資源,如投影資訊,不需要顯式釋放,因為它們只是每查詢記憶體背景關系中的記憶體,)然而……在ExecEndNode期間不需要這樣做,因為FreeExecutorState會釋放EState中的任何剩余的ExprContexts,讓FreeExecutorState這樣做,可以讓ExprContexts以相反的創建順序被釋放,而不是像我們在這里洗掉它們時那樣按照創建順序被釋放,這就節省了在FreeExprContext中清除串列的O(N^2)作業, Postgres行程負責執行客戶端發出的所有的SQL陳述句及自定義函式,在opengauss中與Postgres行程相關的代碼在src/gusskernel/process/tcop/postgres.cpp檔案中,Postgres行程的入口函式是PostgresMain, 陳述句exec_simple_query(query_string)負責決議SQL陳述句,生成查詢計劃,執行查詢計劃,將查詢結果回傳給客戶端,我們組主要進行分析的是opengauss執行查詢計劃的程序,<o:p></o:p> <o:p> 2、執行器的整體執行流程執行器(executor)采用優化器創建的計劃,并對其進行遞回處理以提取所需的行的集合,這本質上是一種需求驅動的流水線執行機制,即每次呼叫一個計劃節點時,它都必須再傳送一行,或者報告已完成傳送所有行, ExecutorRun ()首先呼叫standard_ExecutorStart()完成查詢,然后ExecutorRun ()函式在之后進行SQL 自調優,即查詢執行完畢時,基于運行時資訊分析查詢計劃問題,standard_ExecutorRun()函式主要做的作業就是運行計劃,在執行程序中會呼叫ExecutePlan完成査詢計劃的執行;該函式的主體部分是一個大的回圈,每一次回圈都通過ExecProcNode函式從計劃節點狀態樹中獲取一個元組,然后對該元組進行相應的處理(增刪查改),然后回傳處理的結果,當ExecProcNode從計劃節點狀態樹中再也取不到有效的元組時結束回圈程序,ExecProcNode的執行程序也和ExecInitNode類似:從計劃節點狀態樹的根節點獲取資料,上層節點為了能夠完成自己的處理將會遞回呼叫ExecProcNode從下層節點獲取輸入資料(一般為元組),然后根據輸入資料進行上層節點對應的處理,最后進行選擇條件的運算和投影運算,并向更上層的節點回傳結果元組的指標,同ExecInitNode 一樣,ExecProcNode 也是一個選擇函式,它會根據要處理的節點的型別呼叫對應的處理函式,例如,對于NestLoop型別的節點,其處理函式為ExecNestLoop,ExecNestLoop函式同樣會對NestLoop型別的兩個子節點呼叫ExecProcNode以獲取輸入資料,如果其子節點還有下層節點,則以同樣的方式遞回呼叫ExecProcNode進行處理,直到到達葉子節點,每一個節點被ExecProcNode處理之后都會回傳一個結果元組,這些結果元組作為上層節點的輸入被處理形成上層節點的結果元組,最終根節點將回傳結果元組, 每當通過ExecProcNode從計劃節點狀態樹中獲得一個結果元組后,ExecutePlan函式將根據整個陳述句的操作型別呼叫相應的函式進行最后的處理,對于不掃描表的簡單查詢(例如select 1),呼叫的是Result節點,通過ExecResult函式直接輸出“査詢”結果,對于需要掃描表的查詢(例如select xx from tablexx這種),系統在掃描完節點后直接回傳結果,而對于增刪改查詢,情況特殊,有一個專門的ModifyTable節點來處理它:主要呼叫了ExecInsert、ExecDelete、ExecUpdate這三個函式進行處理,對于插入陳述句,則首先需要呼叫ExecConstraints對即將插入的元組進行約束檢査,如果滿足要求,ExecInsert會呼叫函式heap_insert將元組存盤到存盤系統,對于洗掉和更新,則分別由 ExecDelete 和 ExecUpdate 呼叫 heap_delete 和 heap_update 完成,清理階段:因為執行器在初始化階段向系統申請了資源,所以在這個階段要完成對資源的清理,入口函式為 ExecutorFinish ()、ExecutorEnd (),ExecutorFinish:此例程必須在最后一次ExecutorRun呼叫之后呼叫,它執行清理操作,比如觸發AFTER觸發器,它與ExecutorEnd是分開的,因為EXPLAIN ANALYZE需要在整個運行時中包含這些操作, standard_ExecutorFinish()主要做的作業就是運行ModifyTable節點,執行佇列后觸發器,除非告訴不需要,ExecutorEnd ():此例程必須在任何查詢計劃執行結束時呼叫,之后會呼叫standard_ExecutorEnd()函式,然后呼叫ExecEndPlan處理執行狀態樹根節點釋放已分配的資源,最后釋放執行器全域狀態EState完成整個執行程序,清理程序的任務主要是回收初始化程序中分配的資源、投影和選擇結構的記憶體、結果元組存盤空間等,計劃節點執行狀態樹清理完之后,ExecutorEnd還將呼叫FreeExecutorState清理執行器全域狀態,(4)函式呼叫關系:對Sort節點的整個查詢執行周期里的節點的函式呼叫堆疊如下:
單獨創建一個exprcontext),每個ExprContext都有自己的“per-tuple”記憶體背景關系,注意,我們沒有對呼叫者的記憶體背景關系做任何假設,每一個元組都在execProcnode中獲得分發函式按節點呼叫函式,之后在三個execScan中一起進行組合掃描,掃描結束回到run函式5、最后回到 ExecutorRun 函式,進行 SQL 自調,查詢執行完畢時,基于運行時資訊分析查詢計劃問題,本次除錯中, 查詢中并沒有問題,之后順利退出此函式, 3、ExecutorFinish & ExecutorEnd 代碼除錯程序以及分析此例程必須在最后一次 ExecutorRun 呼叫之后呼叫,它執行清理,例如觸發 AFTER 觸發器,它與 ExecutorEnd 是分開的,因為 EXPLAIN ANALYZE 需要在總運行時間中包含這些操作,除錯程序如下:1、ExecutorFinish這一部分代碼比較簡短,依舊是用select </em> from student;來觀察;2、hook 上同樣被掛載了函式 explain_ExecutorFinish ,該函式的任務依舊是在清理時跟蹤嵌套深度,如果深度超出限制則拋出例外,該部分執行結束后退出,3、進入standard_ExecutorFinish(queryDesc),該部分標準執行代碼比較短:主要是運行 ModifyTable 節點完成 以及執行佇列后觸發器,除非被告知不要;4、最后輪到 ExecutorEnd:</p>
<p><img src=)
FreeExecutorState*釋放一個EState以及所有剩余的作業存盤,</p>
<p><em>注意:這不是負責釋放非記憶體資源,如打開關系或緩沖引腳,但是它將關閉EState內任何仍然活躍的exprcontext,對于EState僅用于運算式求值而不是運行完整的Plan的情況,這已經是足夠的清理作業了</em>這可以在任何記憶體背景關系中呼叫…只要它不是被釋放的那一種,</p>
<p><img src=)
運行機制:1、Postgres行程opengauss與PostgreSQL類似,是多行程結構的資料庫,在PostgreSQL中主要有postmaster, postgres, vacuum, bgwriter, pgarch, walwriter, pgstat等行程,postmaster負責在啟動資料庫的時候創建共享記憶體 并初始化各種內部資料結構,如鎖表,資料庫緩沖區等,該行程在資料庫中只有一個,在資料庫啟動以后負責監聽用戶 請求,創建postgres行程來為用戶服務,,命令型別的代碼是“Q”,主要的處理代碼如下:<img src=)
,因此,執行器以遞回方式呼叫自身以處理其子計劃(如從左子樹的子計劃開始),Merge Join由于要做歸并操作,因此它要子計劃按序回傳元組,從圖中可以看出,它的子計劃是一個Sort節點,Sort的子節點可能是Seq Scan節點,代表對表的實際讀取,執行SeqScan節點會使執行程式從表中獲取一行并將其回傳到呼叫節點,Sort節點將反復呼叫其子節點以獲得所有要排序的行,當輸入完畢時(如子節點回傳NULL而不是新行),Sort算子對獲取的元組進行排序,它每次回傳1個元組,即已排序的第1行,然后不斷排序并向父節點傳遞剩余的排好序的元組,</p>
<p>如圖所示的執行計劃樹示例,頂部節點是Merge Join節點,在進行任何合并操作之前,必須獲取2個元組(MergeJoin節點的2個子計劃各回傳1個元組),因此,執行器以遞回方式呼叫自身以處理其子計劃(如從左子樹的子計劃開始),<o:p></o:p></p>
<p>Merge Join由于要做歸并操作,因此它要子計劃按序回傳元組,從圖中可以看出,它的子計劃是一個Sort節點,Sort的子節點可能是Seq Scan節點,代表對表的實際讀取,執行SeqScan節點會使執行程式從表中獲取一行并將其回傳到呼叫節點,Sort節點將反復呼叫其子節點以獲得所有要排序的行,當輸入完畢時(如子節點回傳NULL而不是新行),Sort算子對獲取的元組進行排序,它每次回傳1個元組,即已排序的第1行,然后不斷排序并向父節點傳遞剩余的排好序的元組,</p>
<p>清理階段,因為執行器在初始化階段向系統申請了資源,所以在這個階段要完成對資源的清理,比如在 HashJoin初始化時對 Hash表記憶體申請的釋放,入口函式為 ExecutorFinish ()、ExecutorEnd ()3、執行器的主要資料結構分析QueryDescs: 查詢描述符,實際是需要執行的SQL陳述句的相關資訊,包含由CreateQueryDesc函式設定的操作型別、規劃器的輸出計劃樹、元組輸出的接收器、查詢環境變數以及由ExecutorStart函式設定的結果元組tuples描述、執行器狀態、和per-plan-node狀態樹,具體結構如下:<img src=)
EState:執行器在呼叫時的主要作業狀態,由ExecutorStart函式設定執行器全域狀態estate中保存了査詢涉及的范圍表(es_range_table)、Estate所在的記憶體背景關系(es_query_cxt,也是執行程序中一直保持的記憶體背景關系)、用于在節點間傳遞元組的全域元組表(es_TupleTable)和每獲取一個元組就會回收的記憶體背景關系(es_per_tuple_exprContext) ,;PlanState:PlanState是所有PlanState-type節點的虛父類執行器初始化時,ExecutorStart會根據査詢計劃樹構造執行器全域狀態(estate)以及計劃節點執行狀態(planstate),在査詢計劃樹的執行程序中,執行器將使用planstate來記錄計劃節點執行狀態和資料,并使用全域狀態記錄中的es_tupleTable欄位在節點間傳遞結果元組,執行器的清理函式ExecutorEnd將回收執行器全域狀態和計劃節點執行狀態,狀態節點之間通過lefttree和righttree指標組織成和査詢計劃樹結構類似的狀態節點樹,同時,每個狀態節點都保存了指向其對應的計劃節點的指標(PlanState型別中的Plan欄位),4、執行器的主要函式分析在opengauss中與執行器主要相關的代碼在src/gusskernel/runtime/executor/execMain.cpp檔案中,主要函式有 ExecutorStart ()、 ExecutorRun ()、ExecutorFinish ()、ExecutorEnd (),初始化階段:在這個階段執行器會完成一些初始化作業,通常的做法是遍歷整個執行樹,根據每個算子的不同特征進行初始化執行,入口函式為ExecutorStart (),這個例程必須在任何查詢計劃的開始執行時呼叫,它接受一個以前由CreateQueryDesc創建的QueryDesc(它是分開的,只是因為一些地方使用QueryDescs實用命令),填充QueryDesc的tupDesc欄位來描述將回傳的元組,并設定內部欄位(estate和planstate),ExecutorStart ()函式代碼如下所示:函式,</p>
<p>standard_ExecutorStart(queryDesc, eflags)函式主要做的作業是:構建EState:呼叫CreateExecutorState()函式,創建每個查詢的背景關系,切換到每個查詢的記憶體背景關系進行啟動;如果是非只讀查詢,設定命令ID以標記輸出元組初始化計劃狀態樹: 呼叫InitPlan(queryDesc, eflags)實作;執行器中對査詢計劃樹的初始化都是從其根節點開始,并遞回地對其子節點進行初始化,計劃節點的初始化程序一般都會經歷如下圖所示的幾個基本步驟,該程序在完成計劃節點的初始化之后會輸出與該計劃節點對應的PlanState結構指標,計劃節點的PlanState結構也會按照査詢計劃樹的結構組織成計劃節點執行狀態樹,對計劃節點初始化的主要作業是根據計劃節點中定義的相關資訊,構造對應的PlanStale結構并對相關欄位賦值,</p>
<p>執行階段,這個階段是執行器最重要的部分,在這個階段,執行器完成對于執行樹的迭代(Pipeline)遍歷,通過從磁盤讀取資料,根據執行樹的具體邏輯完成查詢語意,入口函式為 ExecutorRun (),<img src=)
實驗中出現的問題以及解決方案(對于未解決問題請將問題列出來)<br /> 1、連接MobaXterm_Personal_20.3失敗,原因:IP地址和用戶與虛擬機系統不匹配、或是網路超時方法:保證虛擬機網路穩定連接,ifconfig命令查找虛擬機ip地址<br /> 2、make失敗,產生error,原因:有很多因素,例如絕對路徑與相對路徑問題、相關檔案權限不夠等;方法:配置環境變數時使用絕對路徑;賦予相關檔案更高權限,必要時更改目錄用戶所屬組,<br /> 3、啟動資料庫失敗:gs_ctl: command not found…原因:沒有在omm用戶下配置環境變數,每次啟動,重新配置相關環境變數再啟動則成功,或者資料庫已打開:another server might be running; Please use the restart command,直接連接便好;或者進入安裝目錄中洗掉pid檔案,再次啟動運行,<br /> 4、連接資料庫失敗、埠被占用原因:有其他行程占用埠,方法:使用netstat命令查看占用埠行程,然后殺掉該行程,重新連接資料庫<br /> 5、除錯中沒有進入到所設定的斷點原因:無法在前端對后端斷點進行Debug方法:對后端Gaussdb進行Debug<br /> 6、Debug時候有時會突然終止(實際不應該終止),原因:未知方法:重啟資料庫<br /> 7、make時總是出現error原因:未知方法:初始化腳本要限制行程數量(一般改為1024)<br /> 8、將環境變數寫入.bash_profile檔案使設定的環境變數永久生效,會導致centos虛擬機螢屏變黑、任務欄不可用,原因:未知方法:將檔案洗掉,按部就班,每次啟動資料庫進行環境變數配置,<br /> (二)對于實驗的感受,建議,意見<br /> 1、感受這次的實驗很艱難,首先在代碼的下載和編譯中就遇到了很多問題,之后除錯的程序中,由于對軟體的不熟練,以及對opengauss內核的茫然,讓我一度以為最終不能完成實驗,但是在最后,通過努力,我認為還是交上了一份不錯的答案,</p>
<p>參考文獻</p>
<p>[1]CSDN博主「Zhangjay」的原創文章,原文鏈接:https://blog.csdn.net/Zhangjay/article/details/6565133<o:p></o:p></p>
<p>[2]CSDN博主「fgh431」的原創文章,原文鏈接:https://blog.csdn.net/zhoutianzi12/article/details/96166289<o:p></o:p></p>
<p>[3]CSDN博主「Gauss松鼠會」的原創文章,原文鏈接:https://blog.csdn.net/GaussDB/article/details/116132257<o:p></o:p></p>
<p>[4]作者:非我在, 出處:http://www.cnblogs.com/flying-tiger/</p>
</div>
</div>
<div id=)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/390447.html
標籤:其他
