執行計划解釋
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement where option can be one of: ANALYZE [ boolean ] VERBOSE [ boolean ] COSTS [ boolean ] SETTINGS [ boolean ] BUFFERS [ boolean ] TIMING [ boolean ] SUMMARY [ boolean ] FORMAT { TEXT | XML | JSON | YAML } |
- ANALYZE:真正執行SQL,默認:F
- VERBOSE:顯示計划的附加消息,包括:計划樹每個節點的輸出的各列、觸發器名字(如有),默認:F
- COSTS:每個計划節點的啟動和總成本,以及估計行數和每行寬度。默認:T
- SETTINGS:包括有關配置參數的信息。具體來說,包括影響查詢計划的選項,其值與內置默認值不同。此參數默認為FALSE
- BUFFERS:顯示關於緩沖區的使用消息,需要與analyze一同使用;顯示的緩沖區信息包括:共享塊、本地塊和臨時塊讀和寫的塊數;共享塊包含着來自於常規表和索引的數據,本地塊包含着來自於臨時表和索引的數據,而臨時塊包含着在排序、哈希、物化計划結點和類似情況中使用的短期工作數據。臟塊的數量表示被這個查詢改變的之前未被修改塊的數量,而寫入塊的數量表示這個后台在查詢處理期間從緩存中替換出去的臟塊的數量。
代價參數
seq_page_cost (floating point) 設置規划器計算一次順序磁盤頁面抓取的開銷。默認值是1.0。 通過設置同名的表空間參數(ALTER TABLESPACE),這個值可以重寫為一個特定的表空間。 random_page_cost (floating point) 設置規划器對一次非順序獲取磁盤頁面的代價估計。默認值是 4.0,可以設置表空間級別。減少這個值(相對於seq_page_cost)將導致系統更傾向於索引掃描;提高它將讓索引掃 描看起來相對更昂貴。你可以一起提高或降低兩個值來改變磁盤 I/O 代價相對於 CPU 代價的重要性。在一個高度緩存化的數據庫中,你應該相對於 CPU 參數降低這兩個值,因為獲取一個已經在 RAM 中的頁面的代價要遠小於通常情況下的代價。 cpu_tuple_cost (floating point) 設置規划器對一次查詢中處理每一行的代價估計。默認值是 0.01 cpu_index_tuple_cost (floating point) 設置規划器對一次索引掃描中處理每一個索引項的代價估計。默認值是 0.005。 cpu_operator_cost (floating point) 設置規划器對於一次查詢中處理每個操作符或函數的代價估計。默認值是 0.0025。 parallel_setup_cost (floating point) 設置規划器對啟動並行工作者進程的代價估計。默認是 1000。 parallel_tuple_cost (floating point) 設置規划器對於從一個並行工作者進程傳遞一個元組給另一個進程的代價估計。默認是 0.1。 min_parallel_table_scan_size (integer) 為必須掃描的表數據量設置一個最小值,掃描的表數據量超過這一個值才會考慮使用並行掃描。如果指定值時沒有單位,則以塊為單位,即BLCKSZ字節,通常為8kB。默認值是8兆字節(8MB)。 min_parallel_index_scan_size (integer) 為必須掃描的索引數據量設置一個最小值,掃描的索引數據量超過這一個值時才會考慮使用並行掃描。 注意並行索引掃描通常並不會觸及整個索引,它是規划器認為該掃描會實際用到的相關頁面的數量。 如果指定值時沒有單位,則以塊為單位,即BLCKSZ字節, 通常為8kB。默認值是512千字節(512kB)。 effective_cache_size (integer) 設置規划器對一個單一查詢可用的有效磁盤緩沖區尺寸的假設。 這個參數會被考慮在使用一個索引的代價估計中,更高的數值會使得索引掃描更可能被使用,更低的數值會使得順序掃描更可能被使用。 在設置這個參數時,你還應該考慮PostgreSQL的共享緩沖區以及將被用於PostgreSQL數據文件的內核磁盤緩沖區,盡管有些數據可能在兩個地方都存在。 另外,還要考慮預計在不同表上的並發查詢數目,因為它們必須共享可用的空間。 這個參數對PostgreSQL分配的共享內存尺寸沒有影響,它也不會保留內核磁盤緩沖,它只用於估計的目的。系統也不會假設在查詢之間數據會保留在磁盤緩沖中。 如果指定值時沒有單位,則以塊為單位,即BLCKSZ字節,通常為8kB。 默認值是 4吉字節(4GB)。 jit_above_cost (floating point) 設置激活JIT編譯的查詢代價,如果查詢代價超過這個值就會激活JIT編譯。執行JIT會消耗一些規划時間,但是能夠加速查詢執行。將這個值設置為-1會禁用JIT編譯。默認值是100000。 jit_inline_above_cost (floating point) 設置JIT編譯嘗試內聯函數和操作符的查詢代價閾值,如果查詢代價超過這個值,JIT編譯就會嘗試內聯。內聯會增加規划時間,但是可以提高執行速度。將這個參數設置成小於jit_above_cost是沒有意義的。將這個參數設置為-1會禁用內聯。默認值是500000。 jit_optimize_above_cost (floating point) 設置JIT編譯應用優化的查詢代價閾值,如果查詢代價超過這個值,JIT編譯就會應用開銷較大的優化。這類優化會增加規划時間,但是更能夠改進執行速度。將這個參數設置成小於jit_above_cost是沒有意義的,並且將它設置成大於jit_inline_above_cost也未必有益。將這個參數設置為-1會禁用開銷較大的優化。默認值是500000。 |
GEQO(遺傳查詢優化)
GEQO是一個使用探索式搜索來執行查詢規划的算法。它可以降低負載查詢的規划時間。 同時,GEQO的檢索是隨機的,因此它的規划可能會不可確定。遺傳查詢規划器(GEQO)是一種使用啟發式搜索來進行查詢規划的算法。它可以降低對於復雜查詢(連接很多表的查詢)的規划時間,但是代價是它產生的計划有時候要差於使用窮舉搜索算法找到的計划。
PostgreSQL中GEQO實現的特點有:
• 一種穩態 GA(遺傳算法)(在種群中替換適應度最差的個體,而不是整代替換)的使用允許對改進的
查詢計划快速收斂。這對在合理時間內處理查詢是最重要的;
• 邊重組雜交的使用特別適合於通過GA為TSP的解決方案保持低丟邊率;
• 遺傳操作符變異被廢棄,這樣不需要修補機制來產生合法的TSP旅行。
GEQO模塊的一部分是從 D. Whitley 的遺傳算法中改編而來。
GEQO模塊允許PostgreSQL查詢優化器支持通過非窮舉搜索高效地處理大量連接的查詢。
遺傳算法會丟棄最不適應的候選。然后通過組合更適合的候選的基因來產生新的候選 — 即使從已知代價低的連接序列隨機選擇片段來創建用於考慮的新序列。這個處理將被重復,直到已經考慮的連接序列的數量達到一個預設值。然后在搜索中任何時候找到的最好的一個將被用來產生最終的計划。
geqo (boolean) 允許或禁止遺傳查詢優化。默認是啟用。 geqo_threshold (integer) 只有當涉及的FROM項數量至少有這么多個的時候,才使用遺傳查詢優化(注意一個FULLOUTER JOIN只被計為一個FROM項)。默認值是 12。對於更簡單的查詢,通常會使用普通的窮舉搜索規划器 geqo_effort (integer) 控制 GEQO 里規划時間和查詢規划的有效性之間的平衡。這個變量必須是 一個范圍從 1到 10 的整數。缺省值是 5,更大的值會增加花在查詢規划上的時間,但是同時也增加了選擇一個高效查詢計划的可能性。 geqo_pool_size (integer) 控制 GEQO 使用的池尺寸,它就是遺傳種群中的個體數目。它必須至少為 2,且有用的 值通常在 100 到 1000 之間。如果它被設置為零(默認設置)則會基於geqo_effort和 查詢中表的數量選擇一個合適的值。 geqo_generations (integer) 控制 GEQO 使用的子代數目。子代的意思是算法的迭代次數。它必須至少是1 ,有用的值范圍和池大小相同。如果設置為零(缺省),那么將基於 geqo_pool_size選取合適的值。 geqo_selection_bias (floating point) 控制 GEQO 使用的選擇偏好。選擇偏好是種群中的選擇壓力。值可以是 1.5 到 2.0 之間,后者是默認值。 geqo_seed (floating point) 控制 GEQO 使用的隨機數生成器的初始值,隨機數生成器用於在連接順序搜索空間中選擇隨機路徑。該值可以從 0 (默認值)到 1。變化該值會改變被探索的連接路徑集合,並且可能導致找到一個更好或更差的路徑。 |
其它執行計划配置項
執行計划配置
enable_bitmapscan (boolean) 允許或禁止查詢規划器使用位圖掃描計划類型。默認值是on。 enable_gathermerge (boolean) 啟用或者禁用查詢規划器對收集歸並計划類型的使用。默認值是on。 enable_hashagg (boolean) 允許或禁用查詢規划器使用哈希聚集計划類型。默認值是on。 enable_hashjoin (boolean) 允許或禁止查詢規划器使用哈希連接計划類型。默認值是on。 enable_indexscan (boolean) 允許或禁止查詢規划器使用索引掃描計划類型。默認值是on。 enable_indexonlyscan (boolean) 允許或禁止查詢規划器使用只用索引掃描計划類型(見第 11.9 節)。默認值是on。 enable_material (boolean) 允許或者禁止查詢規划器使用物化。它不可能完全禁用物化,但是關閉這個變量將阻止 規划器插入物化節點,除非為了保證正確性。默認值是on。 enable_mergejoin (boolean) 允許或禁止查詢規划器使用歸並連接計划類型。默認值是on。 enable_nestloop (boolean) 允許或禁止查詢規划器使用嵌套循環連接計划。它不可能完全禁止嵌套循環連接,但是關閉這個變量將使得規划器盡可能優先使用其他方法。默認值是on。 enable_parallel_append (boolean) 允許或禁止查詢規划器使用並行追加計划類型。默認值是on。 enable_parallel_hash (boolean) 允許或禁止查詢規划器對並行哈希使用哈希連接計划類型。如果哈希連接計划也沒有啟用,這個參數沒有效果。默認值是on。 enable_partition_pruning (boolean) 允許或者禁止查詢規划器從查詢計划中消除一個分區表的分區。這也控制着規划器產生允許執行器在查詢執行期間移除(忽略)分區的查詢計划的能力。默認值是on。詳情請參考第 5.11.4 節。 enable_partitionwise_join (boolean) 允許或者禁止查詢規划器使用面向分區的連接,這使得分區表之間的連接以連接匹配的分區的方式來執行。面向分區的連接當前只適用於連接條件包括所有分區鍵的情況,連接條件必須是相同的數據類型並且子分區集合要完全匹配。由於面向分區的連接規划在規划期間會使用可觀的CPU時間和內存,所以默認值為off。 enable_partitionwise_aggregate (boolean) 允許或者禁止查詢規划器使用面向分區的分組或聚集,這使得在分區表上的分組或聚集可以在每個分區上分別執行。如果GROUP BY子句不包括分區鍵,只有部分聚集能夠以基於每個分區的方式執行,並且finalization必須最后執行。由於面向分區的分組或聚集在規划期間會使用可觀的CPU時間和內存,所以默認值為off。 enable_seqscan (boolean) 允許或禁止查詢規划器使用順序掃描計划類型。它不可能完全禁止順序掃描,但是關閉這個變量將使得規划器盡可能優先使用其他方法。默認值是on。 enable_sort (boolean) 允許或禁止查詢規划器使用顯式排序步驟。它不可能完全禁止顯式排序,但是關閉這個變量將使得規划器盡可能優先使用其他方法。默認值是on。 enable_tidscan (boolean) 允許或禁止查詢規划器使用TID掃描計划類型。默認值是on。 |
執行計划節點類型
在PostgreSQL的執行計划中,是自上而下閱讀的,通常執行計划會有相關的索引來表示不同的計划節點,其中計划節點類型分為四類:控制節點(Control Node),掃描節點(Scan Node),物化節點(Materialization Node),連接節點(Join Node)。
控制節點:append,組織多個字表或子查詢的執行節點,主要用於union操作。 掃描節點:用於掃描表等對象以獲取元組 Seq Scan(全表掃描):把表的所有數據塊從頭到尾讀一遍,篩選出符合條件的數據塊; Index Scan(索引掃描):為了加快查詢速度,在索引中找到需要的數據行的物理位置,再到表數據塊中把對應數據讀出來,如B樹,GiST,GIN,BRIN,HASH Bitmap Index/Heap Scan(位圖索引/結果掃描):把滿足條件的行或塊在內存中建一個位圖,掃描完索引后,再根據位圖列表的數據文件把對應的數據讀出來,先通過Bitmap Index Scan在索引中找到符合條件的行,在內存中建立位圖,之后再到表中掃描Bitmap Heap Scan。 物化節點:能夠緩存執行結果到緩存中,即第一次被執行時生成的結果元組緩存,等待上層節點使用,例如,sort節點能夠獲取下層節點返回的所有元組並根據指定的屬性排序,並將排序結果緩存,每次上層節點取元組時就從緩存中按需讀取。 Materialize:對下層節點返回的元組進行緩存(如連接表時) Sort:對下層返回的節點進行排序(如果內存超過iwork_mem參數指定大小,則節點工作空間切換到臨時文件,性能急劇下降) Group:對下層排序元組進行分組操作 Agg:執行聚集函數(sum/max/min/avg) 條件過濾,一般在where后加上過濾條件,當掃描數據行時,會找出滿足過濾條件的行,條件過濾在執行計划里面顯示Filter,如果條件的列上面有索引,可能會走索引,不會走過濾。 連接節點:對應於關系代數中的連接操作,可以實現多種連接方式(條件連接/左連接/右連接/全連接/自然連接) Nestedloop Join(嵌套連接): 內表被外表驅動,外表返回的每一行都要在內表中檢索找到與它匹配的行,因此整個查詢返回的結果集不能太大,要把返回子集較小的表作為外表,且內表的連接字段上要有索引。 執行過程為,確定一個驅動表(outer table),另一個表為inner table,驅動表中每一行與inner table中的相應記錄關聯; Hash Join(哈希連接):優化器使用兩個比較的表,並利用連接屬性在內存中建立散列表,然后掃描較大的表並探測散列表,找出與散列表匹配的行; Merge Join(合並連接):通常hash連接的性能要比merge連接好,但如果源數據上有索引,或結果已經被排過序,這時merge連接性能會優於hash連接; |
運算類型
運算類型 |
操作說明 |
是否有啟動時間 |
Seq Scan |
順序掃描表 |
無啟動時間 |
Index Scan |
索引掃描 |
無啟動時間 |
Bitmap Index Scan |
索引掃描 |
有啟動時間 |
Bitmap Heap Scan |
索引掃描 |
有啟動時間 |
Subquery Scan |
子查詢 |
無啟動時間 |
Tid Scan |
行號檢索 |
無啟動時間 |
Function Scan |
函數掃描 |
無啟動時間 |
Nested Loop Join |
嵌套連接 |
無啟動時間 |
Merge Join |
合並連接 |
有啟動時間 |
Hash Join |
哈希連接 |
有啟動時間 |
Sort |
排序(order by) |
有啟動時間 |
Hash |
哈希運算 |
有啟動時間 |
Result |
函數掃描,和具體的表無關 |
無啟動時間 |
Unique |
distinct/union |
有啟動時間 |
Limit |
limit/offset |
有啟動時間 |
Aggregate |
count, sum,avg等聚集函數 |
有啟動時間 |
Group |
group by |
有啟動時間 |
Append |
union操作 |
無啟動時間 |
Materialize |
子查詢 |
有啟動時間 |
SetOp |
intersect/except |
有啟動時間 |