您好,登錄后才能下訂單哦!
一般來說,閱讀執(zhí)行計(jì)劃通常采用自底往上的方法,這好比從樹的某片葉子出發(fā)然后再到樹枝再到樹干、樹根這么一種方法來了解一顆樹,這種方法存在的問題是如果這顆樹很大,那么就可能出現(xiàn)“只見葉子不見樹干”難以把握整體的情況。這時(shí)候可以結(jié)合自頂往下的方法進(jìn)行閱讀,從而在整體把握整個(gè)執(zhí)行計(jì)劃。
為了更好的理解和使用自頂往下的閱讀方法,需要預(yù)先掌握一些基礎(chǔ)知識(shí).
計(jì)劃節(jié)點(diǎn)類型
在PostgreSQL中,計(jì)劃節(jié)點(diǎn)分為四類,分別是控制節(jié)點(diǎn)(Control Node)、掃描節(jié)點(diǎn)(ScanNode),物化節(jié)點(diǎn)(Materialization Node)、連接節(jié)點(diǎn)(Join Node) 。
1.控制節(jié)點(diǎn):是一類用于處理特殊情況的節(jié)點(diǎn),用于實(shí)現(xiàn)特殊的執(zhí)行流程。例如,Result節(jié)點(diǎn)可用來表示INSERT語句中VALUES子句指定的將要插人的元組。
2.掃描節(jié)點(diǎn):此類節(jié)點(diǎn)用于掃描表等對(duì)象以從中獲取元組。例如,SeqScan節(jié)點(diǎn)用于順序掃描一個(gè)表.毎次掃描一個(gè)元組。
3.物化節(jié)點(diǎn):這類節(jié)點(diǎn)種類比較復(fù)雜,但它們有一個(gè)共同特點(diǎn),即能夠緩存執(zhí)行結(jié)果到輔助存儲(chǔ)中。物化節(jié)點(diǎn)會(huì)在第一次被執(zhí)行時(shí)生成其中的所有結(jié)果元組,然后將這些結(jié)果元組緩存起來,等待其上層節(jié)點(diǎn)取用;而非物化節(jié)點(diǎn)則是每次被執(zhí)行時(shí)生成一個(gè)結(jié)果元組并返回給上層節(jié)點(diǎn)。例如,Sort節(jié)點(diǎn)能夠獲取下層節(jié)點(diǎn)返回的所有元組并根據(jù)指定的屬性進(jìn)行排序,并將排序結(jié)果全部緩存起來,每次上層節(jié)點(diǎn)從Sort節(jié)點(diǎn)取元組時(shí)就從緩存中按順序返回下一個(gè)元組。
4.連接節(jié)點(diǎn):此類節(jié)點(diǎn)對(duì)應(yīng)于關(guān)系代數(shù)中的連接操作,可以實(shí)現(xiàn)多種連接方式(條件連接、左連接、右連接、全連接、自然連接等),每種節(jié)點(diǎn)實(shí)現(xiàn)一種連接算法。例如,HashJoin實(shí)現(xiàn)了基于Hash的連接箅法。
為了方便起見,在此基礎(chǔ)上進(jìn)行推廣,設(shè)置規(guī)則:如控制節(jié)點(diǎn)/物化節(jié)點(diǎn)的子節(jié)點(diǎn)為連接節(jié)點(diǎn),則視為連接節(jié)點(diǎn),否則視為非連接節(jié)點(diǎn).
根據(jù)這條規(guī)則,可以把所有的節(jié)點(diǎn)分為兩類,即連接節(jié)點(diǎn)和非連接節(jié)點(diǎn).
自頂往下的方法,顧名思義,從執(zhí)行計(jì)劃的最頂端/最外層進(jìn)行閱讀.
1.識(shí)別節(jié)點(diǎn)類型(非連接節(jié)點(diǎn) vs 連接節(jié)點(diǎn))
2.如為非連接節(jié)點(diǎn),則識(shí)別該節(jié)點(diǎn)的具體類型(數(shù)據(jù)表掃描...),該分支結(jié)束
3.如為連接節(jié)點(diǎn),則識(shí)別連接的outer端和inner端
3.1 對(duì)outer端遞歸應(yīng)用1/2/3步驟
3.2 對(duì)inner端遞歸應(yīng)用1/2/3步驟
下面舉例說明,SQL腳本如下:
testdb=# explain verbose select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je
testdb-# from t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je
testdb(# from t_grxx gr inner join t_jfxx jf
testdb(# on gr.dwbh = dw.dwbh
testdb(# and gr.grbh = jf.grbh) grjf
testdb-# where dw.dwbh in ('1001','1002')
testdb-# order by dw.dwbh;
QUERY PLAN
-------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.87..61.01 rows=20 width=47)
Output: dw.dwmc, dw.dwbh, dw.dwdz, gr.grbh, gr.xm, jf.ny, jf.je
-> Nested Loop (cost=0.58..53.88 rows=20 width=32)
Output: dw.dwmc, dw.dwbh, dw.dwdz, gr.grbh, gr.xm
-> Index Scan using t_dwxx_pkey on public.t_dwxx dw (cost=0.29..13.92 rows=2 width=20)
Output: dw.dwmc, dw.dwbh, dw.dwdz
Index Cond: ((dw.dwbh)::text = ANY ('{1001,1002}'::text[]))
-> Index Scan using idx_t_grxx_dwbh on public.t_grxx gr (cost=0.29..19.88 rows=10 width=16)
Output: gr.dwbh, gr.grbh, gr.xm, gr.xb, gr.nl
Index Cond: ((gr.dwbh)::text = (dw.dwbh)::text)
-> Index Scan using idx_t_jfxx_grbh on public.t_jfxx jf (cost=0.29..0.35 rows=1 width=20)
Output: jf.grbh, jf.ny, jf.je
Index Cond: ((jf.grbh)::text = (gr.grbh)::text)
(13 rows)
1.識(shí)別節(jié)點(diǎn)類型: Nested Loop -> 連接節(jié)點(diǎn)
3.連接節(jié)點(diǎn):識(shí)別outer端,即通常所說的驅(qū)動(dòng)表(這里是Nested Loop)和inner端(Index Scan).
3.1 outer端為連接節(jié)點(diǎn),類型為Nested Loop
遞歸應(yīng)用1/2/3步驟,解析該Nested Loop
3.1.1 outer端為Index Scan on t_dwxx
3.1.2 inner端為Index Scan on t_grxx
3.2 inner端,遞歸應(yīng)用1/2/3步驟,即Index Scan on t_jfxx
采用自頂往下的方法,可以從"大局"上對(duì)執(zhí)行計(jì)劃上進(jìn)行把握,避免一開始就進(jìn)入繁雜的細(xì)節(jié)之中.
PgSQL · 最佳實(shí)踐 · EXPLAIN 使用淺析
跟我一起讀postgresql源碼(九)
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。