PostgreSQL Executor(3): 可優(yōu)化語句的執(zhí)行

可優(yōu)化語句經(jīng)過優(yōu)化器優(yōu)化后生成查詢計劃樹洞慎,并由Executor執(zhí)行告抄。Executor對外有四個接口函數(shù):ExecutorStart痒玩、ExecutorRunExecutorFinish搂妻、ExecutorEnd蒙保。Executor的輸入是查詢描述符QueryDesc,輸出是結(jié)果數(shù)據(jù)或相關(guān)的執(zhí)行信息欲主。

查詢描述符封裝了Executor執(zhí)行查詢需要的一切信息邓厕。QueryDesc定義在src/include/executor/execdesc.h中逝嚎。

執(zhí)行查詢計劃樹,只需要構(gòu)造QueryDesc详恼,并依次調(diào)用上面四個接口函數(shù)就能完成執(zhí)行過程补君。

Executor的接口函數(shù)全部在Portal的執(zhí)行過程中被調(diào)用。以PORTAL_ONE_SELECT的執(zhí)行策略為例:

  1. PortalStart中首先確定執(zhí)行策略昧互。如果執(zhí)行策略是PORTAL_ONE_SELECT赚哗,則會創(chuàng)建QueryDesc,將查詢計劃樹賦給查詢描述符。然后執(zhí)行ExecutorStart完成Executor的初始化工作硅堆。

  2. PortalRun中調(diào)用PortalRunSelect,在其中執(zhí)行ExecutorRun贿讹,完成查詢計劃的執(zhí)行渐逃。

  3. PortalDrop中調(diào)用PortalCleanup,在其中執(zhí)行ExecutorFinishExecutorEnd以清理環(huán)境民褂,最后釋放QueryDesc茄菊。

Executor的處理模式

Executor對查詢計劃樹的執(zhí)行過程,實際上是對計劃樹的每一個節(jié)點的處理赊堪。查詢樹的每一個節(jié)點都表示一種操作面殖,節(jié)點的處理被設(shè)計成按需要驅(qū)動的模式。節(jié)點使用子節(jié)點輸出的數(shù)據(jù)作為輸入哭廉,按自身的操作邏輯處理之后向上層節(jié)點返回結(jié)果數(shù)據(jù)脊僚。實現(xiàn)上,從根節(jié)點開始處理遵绰,每個節(jié)點在處理過程中根據(jù)需要調(diào)用子節(jié)點的處理過程來獲取數(shù)據(jù)辽幌。通過遞歸的方式,實現(xiàn)整個計劃樹的遍歷執(zhí)行椿访。

初始化和清理操作也是采用相同的模式乌企,從根節(jié)點開始遞歸處理子節(jié)點。

計劃樹中的每一個節(jié)點都是一個操作符成玫,完成一個具體的物理操作加酵。在PostgreSQL中,操作符被定義為有0~2個輸入和1個輸出哭当。這樣所有的操作符可以組織成一個二叉樹猪腕,下層節(jié)點的輸出是上層節(jié)點的輸入,直至根節(jié)點對外輸出結(jié)果數(shù)據(jù)荣病。數(shù)據(jù)(元組)從葉子節(jié)點向上層節(jié)點流動码撰,直至根節(jié)點完成處理。

在Executor中个盆,通過ExecInitNode脖岛、ExecProcNodeExecEndNode三個入口函數(shù)統(tǒng)一對節(jié)點進(jìn)行初始化朵栖、執(zhí)行和清理。每個節(jié)點都實現(xiàn)了對應(yīng)的初始化柴梆、執(zhí)行和清理函數(shù)陨溅,并且通過三個入口函數(shù)從根節(jié)點開始遞歸執(zhí)行。

PostgreSQL采用一次一個元組的執(zhí)行模式绍在,每個節(jié)點一次向上層節(jié)點返回一個元組门扇。整個查詢計劃樹的節(jié)點就構(gòu)成了一個管道,查詢計劃樹的執(zhí)行過程可以看成拉動元組穿過管道的過程偿渡。

計劃節(jié)點的數(shù)據(jù)結(jié)構(gòu)

PostgreSQL采用面向?qū)ο蟮乃枷朐O(shè)計節(jié)點的數(shù)據(jù)結(jié)構(gòu)臼寄,所有節(jié)點都繼承自PlanPlan是所有節(jié)點的通用抽象類型溜宽。

Plan的定義在src/include/nodes/plannodes.h中吉拳,定義如下:

/* ----------------
 *        Plan node
 *
 * All plan nodes "derive" from the Plan structure by having the
 * Plan structure as the first field.  This ensures that everything works
 * when nodes are cast to Plan's.  (node pointers are frequently cast to Plan*
 * when passed around generically in the executor)
 *
 * We never actually instantiate any Plan nodes; this is just the common
 * abstract superclass for all Plan-type nodes.
 * ----------------
 */
typedef struct Plan
{
    NodeTag     type;

    /*
     * estimated execution costs for plan (see costsize.c for more info)
     */
    Cost        startup_cost;   /* cost expended before fetching any tuples */
    Cost        total_cost;     /* total cost (assuming all tuples fetched) */

    /*
     * planner's estimate of result size of this plan step
     */
    double      plan_rows;      /* number of rows plan is expected to emit */
    int         plan_width;     /* average row width in bytes */

    /*
     * information needed for parallel query
     */
    bool        parallel_aware; /* engage parallel-aware logic? */
    bool        parallel_safe;  /* OK to use as part of parallel plan? */

    /*
     * Common structural data for all Plan types.
     */
    int         plan_node_id;   /* unique across entire final plan tree */
    List       *targetlist;     /* target list to be computed at this node */
    List       *qual;           /* implicitly-ANDed qual conditions */
    struct Plan *lefttree;      /* input plan tree(s) */
    struct Plan *righttree;
    List       *initPlan;       /* Init Plan nodes (un-correlated expr
                                 * subselects) */

    /*
     * Information for management of parameter-change-driven rescanning
     *
     * extParam includes the paramIDs of all external PARAM_EXEC params
     * affecting this plan node or its children.  setParam params from the
     * node's initPlans are not included, but their extParams are.
     *
     * allParam includes all the extParam paramIDs, plus the IDs of local
     * params that affect the node (i.e., the setParams of its initplans).
     * These are _all_ the PARAM_EXEC params that affect this node.
     */
    Bitmapset  *extParam;
    Bitmapset  *allParam;
} Plan;

Plan中定義了左右子樹(lefttree, righttree)、節(jié)點類型(type)适揉、選擇表達(dá)式(qual)留攒、投影列表(targetlist)等公共字段。

PostgreSQL將所有的計劃節(jié)點按功能分為四類:

  • 控制節(jié)點(control node)
  • 掃描節(jié)點(scan node)
  • 連接節(jié)點(join node)
  • 物化節(jié)點(materalization node)

其中嫉嘀,掃描和連接節(jié)點類型定義了公共父類ScanJoin炼邀。具體的節(jié)點繼承了公共父類并增加了與自身操作相關(guān)的擴(kuò)展字段。

節(jié)點通過左右子樹指針鏈接了子節(jié)點剪侮,根節(jié)點指針保存在PlannedStmt中拭宁。而PlannedStmt被存放在QueryDesc`中。

PostgreSQL為每一種計劃節(jié)點定義了一個狀態(tài)節(jié)點票彪。與計劃節(jié)點類似红淡,所有的狀態(tài)節(jié)點都繼承自PlanState,其中包含計劃節(jié)點指針降铸、執(zhí)行器全局狀態(tài)結(jié)構(gòu)指針在旱、投影運算信息、選擇運算條件推掸,以及左右子狀態(tài)節(jié)點指針桶蝎。狀態(tài)節(jié)點之間組成了與計劃樹類似的狀態(tài)樹。

在執(zhí)行器初始化時谅畅,ExecutorStart會根據(jù)查詢計劃樹構(gòu)造執(zhí)行器全局狀態(tài)(EState)以及計劃節(jié)點狀態(tài)樹登渣。在查詢樹執(zhí)行過程中,執(zhí)行器將使用狀態(tài)節(jié)點記錄計劃節(jié)點的執(zhí)行狀態(tài)和數(shù)據(jù)毡泻,并通過全局狀態(tài)在節(jié)點間傳遞元組胜茧。執(zhí)行器的清理函數(shù)ExecutorEnd將回收執(zhí)行器全局狀態(tài)和狀態(tài)節(jié)點。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市呻顽,隨后出現(xiàn)的幾起案子雹顺,更是在濱河造成了極大的恐慌,老刑警劉巖廊遍,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嬉愧,死亡現(xiàn)場離奇詭異,居然都是意外死亡喉前,警方通過查閱死者的電腦和手機(jī)没酣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卵迂,“玉大人裕便,你說我怎么就攤上這事〖洌” “怎么了闪金?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長论颅。 經(jīng)常有香客問我,道長囱嫩,這世上最難降的妖魔是什么恃疯? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮墨闲,結(jié)果婚禮上今妄,老公的妹妹穿的比我還像新娘。我一直安慰自己鸳碧,他們只是感情好盾鳞,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞻离,像睡著了一般腾仅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上套利,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天推励,我揣著相機(jī)與錄音,去河邊找鬼肉迫。 笑死验辞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喊衫。 我是一名探鬼主播跌造,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼族购!你這毒婦竟也來了壳贪?” 一聲冷哼從身側(cè)響起陵珍,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撑碴,沒想到半個月后撑教,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡醉拓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年伟姐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亿卤。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡愤兵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出排吴,到底是詐尸還是另有隱情秆乳,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布钻哩,位于F島的核電站屹堰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏街氢。R本人自食惡果不足惜扯键,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望珊肃。 院中可真熱鬧荣刑,春花似錦、人聲如沸伦乔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烈和。三九已至爱只,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間招刹,已是汗流浹背虱颗。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留蔗喂,地道東北人忘渔。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像缰儿,于是被迫代替她去往敵國和親畦粮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • --- layout: post title: "如果有人問你關(guān)系型數(shù)據(jù)庫的原理,叫他看這篇文章(轉(zhuǎn))" date...
    藍(lán)墜星閱讀 780評論 0 3
  • 不可優(yōu)化語句包括DDL宣赔、DCL等预麸。與DML語句不同,它們的處理方式是為每一個類型的語句提供相應(yīng)的處理函數(shù)儒将。 Pos...
    DavidLi2010閱讀 771評論 0 52
  • Zookeeper用于集群主備切換吏祸。 YARN讓集群具備更好的擴(kuò)展性。 Spark沒有存儲能力钩蚊。 Spark的Ma...
    Yobhel閱讀 7,255評論 0 34
  • 從看到華為辭退34歲以上老員工開始贡翘,內(nèi)心受到很大的沖擊。也許現(xiàn)在還在大公司打工的你是個白領(lǐng)砰逻,不愁吃穿鸣驱,每月有豐厚的...
    藝州海棠閱讀 408評論 0 0
  • 1. 今天我很豐盛。早上起來給家人做早餐蝠咆,嘗試新的做法踊东。反響不錯。 2. 今天我很豐盛刚操。手上有好幾件事情要同時進(jìn)行...
    daodaobai閱讀 104評論 0 0