暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL 14 preview - 优化器增强 Rework planning and execution of UPDATE and DELETE. (减少传导不必要的列value、避免为每个分区生成subplan)

digoal 2021-01-04
493

作者

digoal

日期

2021-04-01

标签

PostgreSQL , 优化器


背景

优化器增强 Rework planning and execution of UPDATE and DELETE.

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=86dc90056dfdbd9d1b891718d2e5614e3e432f35

1、减少传导不必要的列value

```
- Output: $1, $2, t.c, (SubPlan 1 (returns $1,$2)), t.ctid
+ Output: $1, $2, (SubPlan 1 (returns $1,$2)), t.ctid
One-Time Filter: (CURRENT_USER = SESSION_USER)
-> Seq Scan on public.update_test t

  • Output: t.c, t.a, t.ctid
  • Output: t.a, t.ctid
    ```

2、避免为每个分区生成subplan

```
- -> Nested Loop (actual rows=0 loops=1)
- -> Append (actual rows=1 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1)
- Recheck Cond: (a = 1)
- Heap Blocks: exact=1
- -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
- -> Materialize (actual rows=0 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
-> Nested Loop (actual rows=1 loops=1)
-> Append (actual rows=1 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1)

  • -> Bitmap Heap Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1)
    ```

```
Rework planning and execution of UPDATE and DELETE.
author Tom Lane tgl@sss.pgh.pa.us
Wed, 31 Mar 2021 15:52:34 +0000 (11:52 -0400)
committer Tom Lane tgl@sss.pgh.pa.us
Wed, 31 Mar 2021 15:52:37 +0000 (11:52 -0400)
commit 86dc90056dfdbd9d1b891718d2e5614e3e432f35
tree 8d281c58f67e90961688fd311673fbdb2f8c35c7 tree
parent 055fee7eb4dcc78e58672aef146334275e1cc40d commit | diff
Rework planning and execution of UPDATE and DELETE.

This patch makes two closely related sets of changes:

  1. For UPDATE, the subplan of the ModifyTable node now only delivers
    the new values of the changed columns (i.e., the expressions computed
    in the query's SET clause) plus row identity information such as CTID.
    ModifyTable must re-fetch the original tuple to merge in the old
    values of any unchanged columns. The core advantage of this is that
    the changed columns are uniform across all tables of an inherited or
    partitioned target relation, whereas the other columns might not be.
    A secondary advantage, when the UPDATE involves joins, is that less
    data needs to pass through the plan tree. The disadvantage of course
    is an extra fetch of each tuple to be updated. However, that seems to
    be very nearly free in context; even worst-case tests don't show it to
    add more than a couple percent to the total query cost. At some point
    it might be interesting to combine the re-fetch with the tuple access
    that ModifyTable must do anyway to mark the old tuple dead; but that
    would require a good deal of refactoring and it seems it wouldn't buy
    all that much, so this patch doesn't attempt it.

  2. For inherited UPDATE/DELETE, instead of generating a separate
    subplan for each target relation, we now generate a single subplan
    that is just exactly like a SELECT's plan, then stick ModifyTable
    on top of that. To let ModifyTable know which target relation a
    given incoming row refers to, a tableoid junk column is added to
    the row identity information. This gets rid of the horrid hack
    that was inheritance_planner(), eliminating O(N^2) planning cost
    and memory consumption in cases where there were many unprunable
    target relations.

Point 2 of course requires point 1, so that there is a uniform
definition of the non-junk columns to be returned by the subplan.
We can't insist on uniform definition of the row identity junk
columns however, if we want to keep the ability to have both
plain and foreign tables in a partitioning hierarchy. Since
it wouldn't scale very far to have every child table have its
own row identity column, this patch includes provisions to merge
similar row identity columns into one column of the subplan result.
In particular, we can merge the whole-row Vars typically used as
row identity by FDWs into one column by pretending they are type
RECORD. (It's still okay for the actual composite Datums to be
labeled with the table's rowtype OID, though.)

There is more that can be done to file down residual inefficiencies
in this patch, but it seems to be committable now.

FDW authors should note several API changes:

  • The argument list for AddForeignUpdateTargets() has changed, and so
    has the method it must use for adding junk columns to the query. Call
    add_row_identity_var() instead of manipulating the parse tree directly.
    You might want to reconsider exactly what you're adding, too.

  • PlanDirectModify() must now work a little harder to find the
    ForeignScan plan node; if the foreign table is part of a partitioning
    hierarchy then the ForeignScan might not be the direct child of
    ModifyTable. See postgres_fdw for sample code.

  • To check whether a relation is a target relation, it's no
    longer sufficient to compare its relid to root->parse->resultRelation.
    Instead, check it against all_result_relids or leaf_result_relids,
    as appropriate.

Amit Langote and Tom Lane

Discussion: https://postgr.es/m/CA+HiwqHpHdqdDn48yCEhynnniahH78rwcrv1rEX65-fsZGBOLQ@mail.gmail.com
```

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论