1. 程式人生 > >PostgreSQL 11 新特性之分割槽裁剪增強

PostgreSQL 11 新特性之分割槽裁剪增強

文章目錄

在之前的版本中,只在查詢的計劃階段執行分割槽排除操作(通過 constraint_exclusion 變數控制),意味著許多連線查詢和預編譯查詢無法使用分割槽排除。另外,這種方法佔用的時間會隨著分割槽的數量線性增長。

PostgreSQL 11 通過兩個方面的改進提供了更加強大且快速的分割槽裁剪功能:

  • 查詢計劃階段更快的分割槽排除,可以提高分割槽表(尤其是包含許多分割槽的分割槽表)的訪問效能。
  • 支援執行階段的分割槽排除。

分割槽裁剪使用選項 enable_partition_pruning 進行控制。該引數預設值為 on。

show enable_partition_pruning;
 enable_partition_pruning 
--------------------------
 on
(1 row)

CREATE TABLE rtable(c1 INT, c2 VARCHAR(10)) PARTITION BY RANGE(c1);
CREATE TABLE rtable100 PARTITION OF rtable FOR VALUES FROM (1) TO (100);
CREATE TABLE rtable200 PARTITION OF rtable FOR VALUES FROM (101) TO
(200); CREATE TABLE rtable300 PARTITION OF rtable FOR VALUES FROM (201) TO (300); CREATE TABLE rtable400 PARTITION OF rtable FOR VALUES FROM (301) TO (400); explain analyze select * from rtable where c1=256; QUERY PLAN -----------------------------------------------------------------------------------------------------------
Append (cost=0.00..24.53 rows=6 width=42) (actual time=0.009..0.009 rows=0 loops=1) -> Seq Scan on rtable300 (cost=0.00..24.50 rows=6 width=42) (actual time=0.007..0.007 rows=0 loops=1) Filter: (c1 = 256) Planning Time: 0.397 ms Execution Time: 0.042 ms (5 rows)

如果將該引數設定為 off,將會禁用分割槽裁剪功能:

set enable_partition_pruning=off;
explain analyze select * from rtable where c1=256;
                                                QUERY PLAN                                                 
-----------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..98.12 rows=24 width=42) (actual time=0.015..0.015 rows=0 loops=1)
   ->  Seq Scan on rtable100  (cost=0.00..24.50 rows=6 width=42) (actual time=0.007..0.007 rows=0 loops=1)
         Filter: (c1 = 256)
   ->  Seq Scan on rtable200  (cost=0.00..24.50 rows=6 width=42) (actual time=0.002..0.002 rows=0 loops=1)
         Filter: (c1 = 256)
   ->  Seq Scan on rtable300  (cost=0.00..24.50 rows=6 width=42) (actual time=0.002..0.002 rows=0 loops=1)
         Filter: (c1 = 256)
   ->  Seq Scan on rtable400  (cost=0.00..24.50 rows=6 width=42) (actual time=0.002..0.002 rows=0 loops=1)
         Filter: (c1 = 256)
 Planning Time: 0.246 ms
 Execution Time: 0.167 ms
(11 rows)

注意 Currently, pruning of partitions during the planning of an UPDATE
目前,對於 UPDATE 和 DELETE 語句,計劃階段的分割槽裁剪基於之前的約束排除方法實現(但是,該功能使用 enable_partition_pruning 選項控制,而不是 constraint_exclusion 選項)。
另外,執行階段的分割槽裁剪目前支援 Append 節點型別,而不支援 MergeAppend 或者 ModifyTable(UPDATE 或者 DELETE)。
這些行為很可能在將來的 PostgreSQL 版本中進行修改。

在 PostgreSQL 11 中,查詢計劃階段的分割槽排除使用二分查詢法搜尋匹配的分割槽(LIST 分割槽表和 RANGE 分割槽表);對於雜湊分割槽表,使用雜湊函式查詢匹配的分割槽。但是,對於 UPDATE/DELETE 語句,仍然使用約束排除的方法。

PostgreSQL 11 另一個重大的改進就是支援查詢執行時的動態分割槽裁剪。先看一個 PostgreSQL 10 中的示例。

-- PostgreSQL 10
PREPARE ps1 (INT) AS SELECT * FROM rtable WHERE c1 = $1;

explain analyze execute ps1(256);
                                                QUERY PLAN                                                 
-----------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..98.00 rows=24 width=42) (actual time=0.051..0.051 rows=0 loops=1)
   ->  Seq Scan on rtable100  (cost=0.00..24.50 rows=6 width=42) (actual time=0.011..0.011 rows=0 loops=1)
         Filter: (c1 = 256)
   ->  Seq Scan on rtable200  (cost=0.00..24.50 rows=6 width=42) (actual time=0.006..0.006 rows=0 loops=1)
         Filter: (c1 = 256)
   ->  Seq Scan on rtable300  (cost=0.00..24.50 rows=6 width=42) (actual time=0.006..0.006 rows=0 loops=1)
         Filter: (c1 = 256)
   ->  Seq Scan on rtable400  (cost=0.00..24.50 rows=6 width=42) (actual time=0.005..0.005 rows=0 loops=1)
         Filter: (c1 = 256)
 Planning time: 0.373 ms
 Execution time: 0.215 ms
(11 rows)

查詢計劃顯示需要掃描所有的分割槽,因為查詢計劃器無法確定帶引數的查詢語句的執行計劃。

以下是相同的操作在 PostgreSQL 11 中的結果:

-- PostgreSQL 11
PREPARE ps1 (INT) AS SELECT * FROM rtable WHERE c1 = $1;

explain analyze execute ps1(256);
                                                QUERY PLAN                                                 
-----------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..24.53 rows=6 width=42) (actual time=0.017..0.019 rows=1 loops=1)
   ->  Seq Scan on rtable300  (cost=0.00..24.50 rows=6 width=42) (actual time=0.016..0.017 rows=1 loops=1)
         Filter: (c1 = 256)
 Planning Time: 0.382 ms
 Execution Time: 0.049 ms
(5 rows)

結果顯示,PostgreSQL 11 可以針對帶引數的查詢語句執行分割槽排除。

動態分割槽排除可以利用查詢的計劃階段不能確定的值執行分割槽裁剪;例如 PREPARE 語句中的引數,通過子查詢獲取的值,或者巢狀迴圈連線的內層引數值。執行時分割槽裁剪髮生在以下兩個時間點:

  • 查詢計劃初始化階段。使用執行初始化階段能夠確定的引數值執行分割槽裁剪。這個階段排除的分割槽不會顯示在 EXPLAIN 或 EXPLAIN ANALYZE 的結果中。可以通過 EXPLAIN 結果的 “Subplans Removed” 屬性檢視這個階段排除的分割槽數量。
  • 查詢計劃的實際執行階段。在查詢的實際執行階段,仍然可能使用執行時才能確定的值完成分割槽裁剪的操作。例如來自子查詢的值和執行時引數(例如引數化的巢狀迴圈連線)的值。由於這些引數的值在執行時可能會發生變化,每次引數變化時都會執行一次分割槽裁剪操作。判斷是否在該階段產生分割槽排除可以查詢 EXPLAIN ANALYZE 輸出中的 nloops 屬性。

以下是一個使用子查詢的示例:

explain analyze select * from rtable where c1=(select 256);
                                                QUERY PLAN                                                
----------------------------------------------------------------------------------------------------------
 Append  (cost=0.01..74.61 rows=19 width=42) (actual time=0.027..0.027 rows=0 loops=1)
   InitPlan 1 (returns $0)
     ->  Result  (cost=0.00..0.01 rows=1 width=4) (actual time=0.002..0.002 rows=1 loops=1)
   ->  Seq Scan on rtable100  (cost=0.00..24.50 rows=6 width=42) (never executed)
         Filter: (c1 = $0)
   ->  Seq Scan on rtable200  (cost=0.00..24.50 rows=6 width=42) (never executed)
         Filter: (c1 = $0)
   ->  Seq Scan on rtable300  (cost=0.00..1.00 rows=1 width=42) (actual time=0.012..0.012 rows=0 loops=1)
         Filter: (c1 = $0)
   ->  Seq Scan on rtable400  (cost=0.00..24.50 rows=6 width=42) (never executed)
         Filter: (c1 = $0)
 Planning Time: 0.301 ms
 Execution Time: 0.103 ms
(13 rows)

查詢計劃中的 (never executed) 就是執行時動態執行的分割槽裁剪。

官方文件:Table Partitioning