PostgreSQL DBA(13) - 自頂往下的方法閱讀執行計劃

husthxd發表於2018-12-06

一般來說,閱讀執行計劃通常採用自底往上的方法,這好比從樹的某片葉子出發然後再到樹枝再到樹幹、樹根這麼一種方法來了解一顆樹,這種方法存在的問題是如果這顆樹很大,那麼就可能出現“只見葉子不見樹幹”難以把握整體的情況。這時候可以結合自頂往下的方法進行閱讀,從而在整體把握整個執行計劃。

一、基礎知識

為了更好的理解和使用自頂往下的閱讀方法,需要預先掌握一些基礎知識.
計劃節點型別

在PostgreSQL中,計劃節點分為四類,分別是控制節點(Control Node)、掃描節點(ScanNode),物化節點(Materialization Node)、連線節點(Join Node) 。
1.控制節點:是一類用於處理特殊情況的節點,用於實現特殊的執行流程。例如,Result節點可用來表示INSERT語句中VALUES子句指定的將要插人的元組。
2.掃描節點:此類節點用於掃描表等物件以從中獲取元組。例如,SeqScan節點用於順序掃描一個表.毎次掃描一個元組。
3.物化節點:這類節點種類比較複雜,但它們有一個共同特點,即能夠快取執行結果到輔助儲存中。物化節點會在第一次被執行時生成其中的所有結果元組,然後將這些結果元組快取起來,等待其上層節點取用;而非物化節點則是每次被執行時生成一個結果元組並返回給上層節點。例如,Sort節點能夠獲取下層節點返回的所有元組並根據指定的屬性進行排序,並將排序結果全部快取起來,每次上層節點從Sort節點取元組時就從快取中按順序返回下一個元組。
4.連線節點:此類節點對應於關係代數中的連線操作,可以實現多種連線方式(條件連線、左連線、右連線、全連線、自然連線等),每種節點實現一種連線演算法。例如,HashJoin實現了基於Hash的連線箅法。

為了方便起見,在此基礎上進行推廣,設定規則:如控制節點/物化節點的子節點為連線節點,則視為連線節點,否則視為非連線節點.
根據這條規則,可以把所有的節點分為兩類,即連線節點非連線節點.

二、自頂往下的方法

自頂往下的方法,顧名思義,從執行計劃的最頂端/最外層進行閱讀.
1.識別節點型別(非連線節點 vs 連線節點)
2.如為非連線節點,則識別該節點的具體型別(資料表掃描...),該分支結束
3.如為連線節點,則識別連線的outer端和inner端
3.1 對outer端遞回應用1/2/3步驟
3.2 對inner端遞回應用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.識別節點型別: Nested Loop -> 連線節點
3.連線節點:識別outer端,即通常所說的驅動表(這裡是Nested Loop)和inner端(Index Scan).
3.1 outer端為連線節點,型別為Nested Loop
遞回應用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端,遞回應用1/2/3步驟,即Index Scan on t_jfxx

採用自頂往下的方法,可以從"大局"上對執行計劃上進行把握,避免一開始就進入繁雜的細節之中.

三、參考資料

PgSQL · 最佳實踐 · EXPLAIN 使用淺析
跟我一起讀postgresql原始碼(九)

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/6906/viewspace-2374786/,如需轉載,請註明出處,否則將追究法律責任。

相關文章