PostgreSQL 10.0 preview 性能增强 - hash,nestloop join优化(聪明的优化器是这样的)

标签

PostgreSQL , 10.0 , nestloop , hash join


背景

两张表JOIN时,如果内表的JOIN字段确定是唯一的,那么在嵌套循环时,如果外表有重复值,循环过程中,对于内表来说,一个VALUE只需要扫描一次。

hash join同样适用。

例子

postgres=# create table intbl(id int);
CREATE TABLE
postgres=# create unique index idx_intbl on intbl(id);
CREATE INDEX
postgres=# insert into intbl select generate_series(1,1000000);
INSERT 0 1000000
postgres=# create table out(id int);
CREATE TABLE
postgres=# insert into out select 1 from generate_series(1,1000);
-- 对于外表的1000个1, 内表scan一次命中后,同一个值不需要再次scan内表
INSERT 0 1000
postgres=# set enable_hashjoin =off;
SET
postgres=# set enable_mergejoin =off;
SET
postgres=# set enable_material =off;
SET

9.6

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from out,intbl where out.id=intbl.id;
                                                              QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.42..2736.00 rows=1000 width=8) (actual time=0.033..1.965 rows=1000 loops=1)
   Output: "out".id, intbl.id
   Buffers: shared hit=4005
   ->  Seq Scan on public."out"  (cost=0.00..15.00 rows=1000 width=4) (actual time=0.013..0.101 rows=1000 loops=1)
         Output: "out".id
         Buffers: shared hit=5
   ->  Index Only Scan using idx_intbl on public.intbl  (cost=0.42..2.71 rows=1 width=4) (actual time=0.001..0.002 rows=1 loops=1000)
         Output: intbl.id
         Index Cond: (intbl.id = "out".id)
         Heap Fetches: 1000
         Buffers: shared hit=4000
 Planning time: 0.109 ms
 Execution time: 2.048 ms
(13 rows)

10.0

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from out,intbl where out.id=intbl.id;
                                                              QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.42..2202.50 rows=1000 width=8) (actual time=0.035..1.803 rows=1000 loops=1)
   Output: "out".id, intbl.id
   Inner Unique: true
   Buffers: shared hit=4005
   ->  Seq Scan on public."out"  (cost=0.00..15.00 rows=1000 width=4) (actual time=0.013..0.106 rows=1000 loops=1)
         Output: "out".id
         Buffers: shared hit=5
   ->  Index Only Scan using idx_intbl on public.intbl  (cost=0.42..2.19 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=1000)
         Output: intbl.id
         Index Cond: (intbl.id = "out".id)
         Heap Fetches: 1000
         Buffers: shared hit=4000
 Planning time: 0.122 ms
 Execution time: 1.887 ms
(14 rows)

patch如下

Optimize joins when the inner relation can be proven unique.  

author	Tom Lane <tgl@sss.pgh.pa.us>
Sat, 8 Apr 2017 10:20:03 +0800 (22:20 -0400)
committer	Tom Lane <tgl@sss.pgh.pa.us>
Sat, 8 Apr 2017 10:20:13 +0800 (22:20 -0400)
commit	9c7f5229ad68d7e0e4dd149e3f80257893e404d4
tree	0a167d403952550f43941b01b24ed5e7526c5351	tree | snapshot
parent	f13a9121f9822eafe05cc3178bf046155a248173	commit | diff
Optimize joins when the inner relation can be proven unique.  

If there can certainly be no more than one matching inner row for a given
outer row, then the executor can move on to the next outer row as soon as
it's found one match; there's no need to continue scanning the inner
relation for this outer row.  This saves useless scanning in nestloop
and hash joins.  In merge joins, it offers the opportunity to skip
mark/restore processing, because we know we have not advanced past the
first possible match for the next outer row.  

Of course, the devil is in the details: the proof of uniqueness must
depend only on joinquals (not otherquals), and if we want to skip
mergejoin mark/restore then it must depend only on merge clauses.
To avoid adding more planning overhead than absolutely necessary,
the present patch errs in the conservative direction: there are cases
where inner_unique or skip_mark_restore processing could be used, but
it will not do so because it's not sure that the uniqueness proof
depended only on "safe" clauses.  This could be improved later.  

David Rowley, reviewed and rather heavily editorialized on by me  

Discussion: https://postgr.es/m/CAApHDvqF6Sw-TK98bW48TdtFJ+3a7D2mFyZ7++=D-RyPsL76gw@mail.gmail.com

这个patch的讨论,详见邮件组,本文末尾URL。

PostgreSQL社区的作风非常严谨,一个patch可能在邮件组中讨论几个月甚至几年,根据大家的意见反复的修正,patch合并到master已经非常成熟,所以PostgreSQL的稳定性也是远近闻名的。

参考

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=9c7f5229ad68d7e0e4dd149e3f80257893e404d4

时间: 2024-09-13 01:19:47

PostgreSQL 10.0 preview 性能增强 - hash,nestloop join优化(聪明的优化器是这样的)的相关文章

PostgreSQL 10.0 preview 性能增强 - hash index metapage cache、高并发增强

标签 PostgreSQL , 10.0 , hash index 背景 hash index是PostgreSQL中一个非常老的索引访问方法,也是非常经典的索引. hash index中存储的是索引字段的hash value,而不是原始值,btree索引中存储的是原始值. 因此,当字段非常大时,btree索引可能无法使用. 例如 postgres=# create table test_hash_btree(c1 text); CREATE TABLE postgres=# insert in

震精 - PostgreSQL 10.0 preview 性能增强 - WARM提升一倍性能

标签 PostgreSQL , 10.0 , WARM , 写放大 , 索引写放大 背景 目前,PostgreSQL的MVCC是多版本来实现的,当更新数据时,产生新的版本.(社区正在着手增加基于回滚段的存储引擎) 由于索引存储的是KEY+CTID(行号),当tuple的新版本与旧版本不在同一个数据块(BLOCK)的时候,索引也要随之变化,当新版本在同一个块里面时,则发生HOT UPDATE,索引的值不需要更新,但是因为产生了一条新的记录,所以也需要插入一条索引item,垃圾回收时,将其回收,因此

PostgreSQL 10.0 preview 性能增强 - 推出JIT开发框架(朝着HTAP迈进)

标签 PostgreSQL , 10.0 , HTAP , 动态编译 , JIT , LLVM , 表达式 , 函数跳转 背景 数据库发展了几十年,出现了很多产品,有面向OLTP(在线事务处理)的,有面向OLAP(在线分析)的. 虽然两个场景各有需求特色,但是企业需要为其需求买单,因为目前很少有产品可以同时满足在线处理和在线分析的需求. 比如一家企业,通常都有业务的波峰波谷,比如游戏业务,通常波谷可能是在凌晨,因为大多数人都睡了.而波峰可能出现在每天的工作闲时.游戏运营时段.节假日等. 为了分析

PostgreSQL 10.0 preview 性能增强 - 分区表性能增强(plan阶段加速)

标签 PostgreSQL , 10.0 , 分区表 , 子表 , 元信息搜索性能增强 背景 PostgreSQL 10.0 增强了分区表的子表搜索性能,对于涉及分区表包含子表特别多的QUERY,可以提升性能. 性能分析 get_tabstat_entry, find_all_inheritors成为主要瓶颈. Hello. I decided to figure out whether current implementation of declarative partitioning has

PostgreSQL 10.0 preview 性能增强 - mergesort(Gather merge)

标签 PostgreSQL , 10.0 , merge sort , gather merge 背景 在数据库中,经常会有多个节点append,然后sort的情况. 例如一张表有10个分区,查询所有分区,并按某列排序输出,常规的做法是所有的记录append,然后sort. PostgreSQL 10.0 将支持append node的并行计算,也就是说所有的分区表可以并行的sort,然后返回,此时就可以使用merge sort来提高排序的速度. 另外,像单表的并行计算,如果需要排序输出的话,每

PostgreSQL 10.0 preview 性能增强 - pg_xact align(cacheline对齐)

标签 PostgreSQL , 10.0 , cacheline对齐 , pgxact 背景 cacheline对齐,可以大幅提升高并发下的性能. Hackers, originally this idea was proposed by Andres Freund while experimenting with lockfree Pin/UnpinBuffer [1]. The patch is attached as well as results of pgbench -S on 72-

PostgreSQL 10.0 preview 性能增强 - (多维分析)更快,更省内存hashed aggregation with grouping sets

标签 PostgreSQL , 10.0 , hashed aggregation with grouping sets 背景 grouping sets 是多维分析语法,PostgreSQL 从9.5开始支持这种语法,常被用于OLAP系统,数据透视等应用场景. <PostgreSQL 9.5 new feature - Support GROUPING SETS, CUBE and ROLLUP.> 由于多维分析的一个QUERY涉及多个GROUP,所以如果使用hash agg的话,需要多个H

PostgreSQL 10.0 preview 性能增强 - OLAP提速框架, Faster Expression Evaluation Framework(含JIT)

标签 PostgreSQL , 10.0 , llvm , jit , Faster Expression Evaluation Framework 背景 PostgreSQL 10.0有可能会融合JIT,向量计算等技术,提供一个通用的,便于高效协作,提升OLAP性能的一个开发框架. 虽然目前社区有朋友已经提供了LLVM和向量计算的插件,很显然社区是想在内核中直接整合这些计算的.加油PostgreSQL <分析加速引擎黑科技 - LLVM.列存.多核并行.算子复用 大联姻 - 一起来开启Post

PostgreSQL 10.0 preview 功能增强 - hash index 支持wal(灾难恢复)

标签 PostgreSQL , 10.0 , hash index , wal , 灾难恢复 背景 PostgreSQL 10.0 将支持hash index WAL. 因此建hash index再也不怕数据库crash或者备库hash index不可用了. $SUBJECT will make hash indexes reliable and usable on standby. AFAIU, currently hash indexes are not recommended to be