【PostgreSQL 】PostgreSQL 15对distinct的优化
示例表
table t_ex;
c1 | c2
----+----
2 | B
4 | C
6 | A
2 | C
4 | B
6 | B
2 | A
4 | B
6 | C
2 | C
以下SQL语句有序地返回"c1"列中唯一值:
select distinct on(c1) * from abce;
对于c2列,会根据c1的唯一性,从表中找到的第一个值。
postgres=# select distinct on(c1) * from abce;
c1 | c2
----+----
2 | B
4 | B
6 | B
(3 rows)
以下SQL语句有序地返回"c2"列中唯一值:
# select distinct on(c2) * from abce;
c1 | c2
----+----
6 | A
2 | B
4 | C
(3 rows)
最后从表中返回唯一性的记录
postgres=# select distinct * from abce;
c1 | c2
----+----
6 | C
4 | C
4 | B
2 | C
2 | A
6 | B
6 | A
2 | B
(8 rows)
那么你可能会问,在postgresql15中,distinct的增强体现在哪些方面呢?答案是:并发
在此之前,只有一个cpu或进程来计算不同的值。在postgresql15中,可以使用并发,使用多个cpu进程。
这一特性涉及好几个参数,但是,我们只聚焦在参数max_parallel_workers_per_gather。
为了演示这个改进,我们创建三个表,没有索引,填充大约5000000条记录。注意,表的列数分别为1,5,10。
Table "public.t1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c1 | integer | | | Table "public.t5"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
c1 | integer | | |
c2 | integer | | |
c3 | integer | | |
c4 | integer | | |
c5 | character varying(40) | | | Table "public.t10"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
c1 | integer | | |
c2 | integer | | |
c3 | integer | | |
c4 | integer | | |
c5 | character varying(40) | | |
c6 | integer | | |
c7 | integer | | |
c8 | integer | | |
c9 | integer | | |
c10 | integer | | |
insert into t1 select generate_series(1,500); insert into t5
select generate_series(1,500)
,generate_series(500,1000)
,generate_series(1000,1500)
,(random()*100)::int
,'aofjaofjwaoeev$#^ÐE#@#Fasrhk!!@%Q@'; insert into t10
select generate_series(1,500)
,generate_series(500,1000)
,generate_series(1000,1500)
,(random()*100)::int
,'aofjaofjwaoeev$#^ÐE#@#Fasrhk!!@%Q@'
,generate_series(1500,2000)
,generate_series(2500,3000)
,generate_series(3000,3500)
,generate_series(3500,4000)
,generate_series(4000,4500); List of relations
Schema | Name | Type | Owner | Persistence | Access method | Size |
--------+------+-------+----------+-------------+---------------+--------+
public | t1 | table | postgres | permanent | heap | 173 MB |
public | t10 | table | postgres | permanent | heap | 522 MB |
public | t5 | table | postgres | permanent | heap | 404 MB |
下一步是将生成的数据dump到以下的版本中:
PG VERSION
pg96
pg10
pg11
pg12
pg13
pg14
pg15
数据导入后,使用下面的脚本生成结果:
#!/bin/bash
for v in 96 10 11 12 13 14 15
do
# run the explain analzye 5X in order to derive consistent numbers
for u in $(seq 1 5)
do
echo "--- explain analyze: pg${v}, ${u}X ---"
psql -p 100$v db01 -c "explain analyze select distinct on (c1) * from t1" > t1.pg$v.explain.txt
psql -p 100$v db01 -c "explain analyze select distinct * from t5" > t5.pg$v.explain.txt
psql -p 100$v db01 -c "explain analyze select distinct * from t10" > t10.pg$v.explain.txt
done
done
以下是结果比较,可以看到表越大,性能收获越大。
|
PG VERSION |
1 column (t1), ms |
5 column (t5), ms |
10 column (t10), ms |
|
pg96 |
3,382 |
9,743 |
20,026 |
|
pg10 |
2,004 |
5,746 |
13,241 |
|
pg11 |
1,932 |
6,062 |
14,295 |
|
pg12 |
1,876 |
5,832 |
13,214 |
|
pg13 |
1,973 |
2,358 |
3,135 |
|
pg14 |
1,948 |
2,316 |
2,909 |
|
pg15 |
1,439 |
1,025 |
1,245 |

来看看不同版本之间的执行计划:
PG96 QUERY PLAN, TABLE T1
-------------------------------------------------------------------------------
Unique (cost=765185.42..790185.42 rows=500 width=4) (actual time=2456.805..3381.230 rows=500 loops=1)
-> Sort (cost=765185.42..777685.42 rows=5000000 width=4) (actual time=2456.804..3163.600 rows=5000000 loops=1)
Sort Key: c1
Sort Method: external merge Disk: 68432kB
-> Seq Scan on t1 (cost=0.00..72124.00 rows=5000000 width=4) (actual time=0.055..291.523 rows=5000000 loops=1)
Planning time: 0.161 ms
Execution time: 3381.662 ms
PG15 QUERY PLAN, TABLE T1
---------------------------------------------------------------------------
Unique (cost=557992.61..582992.61 rows=500 width=4) (actual time=946.556..1411.421 rows=500 loops=1)
-> Sort (cost=557992.61..570492.61 rows=5000000 width=4) (actual time=946.554..1223.289 rows=5000000 loops=1)
Sort Key: c1
Sort Method: external merge Disk: 58720kB
-> Seq Scan on t1 (cost=0.00..72124.00 rows=5000000 width=4) (actual time=0.038..259.329 rows=5000000 loops=1)
Planning Time: 0.229 ms
JIT:
Functions: 1
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 0.150 ms, Inlining 31.332 ms, Optimization 6.746 ms, Emission 6.847 ms, Total 45.074 ms
Execution Time: 1438.683 ms
当DISTINCT列的数量增加时,真正的差异出现了,如查询表 t10 所示。 可以看到并行化在起作用!
PG96 QUERY PLAN, TABLE T10
-------------------------------------------------------------------------------------------
Unique (cost=1119650.30..1257425.30 rows=501000 width=73) (actual time=14257.801..20024.271 rows=50601 loops=1)
-> Sort (cost=1119650.30..1132175.30 rows=5010000 width=73) (actual time=14257.800..19118.145 rows=5010000 loops=1)
Sort Key: c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
Sort Method: external merge Disk: 421232kB
-> Seq Scan on t10 (cost=0.00..116900.00 rows=5010000 width=73) (actual time=0.073..419.701 rows=5010000 loops=1)
Planning time: 0.352 ms
Execution time: 20025.956 ms
PG15 QUERY PLAN, TABLE T10
------------------------------------------------------------------------------------------- HashAggregate (cost=699692.77..730144.18 rows=501000 width=73) (actual time=1212.779..1232.667 rows=50601 loops=1)
Group Key: c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
Planned Partitions: 16 Batches: 17 Memory Usage: 8373kB Disk Usage: 2976kB
-> Gather (cost=394624.22..552837.15 rows=1002000 width=73) (actual time=1071.280..1141.814 rows=151803 loops=1)
Workers Planned: 2
Workers Launched: 2
-> HashAggregate (cost=393624.22..451637.15 rows=501000 width=73) (actual time=1064.261..1122.628 rows=50601 loops=3)
Group Key: c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
Planned Partitions: 16 Batches: 17 Memory Usage: 8373kB Disk Usage: 15176kB
Worker 0: Batches: 17 Memory Usage: 8373kB Disk Usage: 18464kB
Worker 1: Batches: 17 Memory Usage: 8373kB Disk Usage: 19464kB
-> Parallel Seq Scan on t10 (cost=0.00..87675.00 rows=2087500 width=73) (actual time=0.072..159.083 rows=1670000 loops=3)
Planning Time: 0.286 ms
JIT:
Functions: 31
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 3.510 ms, Inlining 123.698 ms, Optimization 200.805 ms, Emission 149.608 ms, Total 477.621 ms
Execution Time: 1244.556 ms
提高性能:
postgres运行时参数max_parallel_workers_per_gather来提高性能。新初始化的集群中的默认值为2。
如下表所示,由于测试硬件本身的能力有限,它很快成为收益递减的原因。
在postgresql 15中:
|
max_parallel_workers_per_gather |
1 column (t1) |
5 column (t5) |
10 column (t10) |
|
2 |
1,439 |
1,025 |
1,245 |
|
3 |
1,464 |
875 |
1,013 |
|
4 |
1,391 |
858 |
977 |
|
6 |
1,401 |
846 |
1,045 |
|
8 |
1,428 |
856 |
993 |

关于索引:如本查询计划中所示,应用索引时未实现性能改进。
PG15,表T10,max_parallel_workers_per_gather=4:
QUERY PLAN
-----------------------------------------------------------------------------------
Unique (cost=0.43..251344.40 rows=501000 width=73) (actual time=0.060..1240.729 rows=50601 loops=1)
-> Index Only Scan using t10_c1_c2_c3_c4_c5_c6_c7_c8_c9_c10_idx on t10 (cost=0.43..126094.40 rows=5010000 width=73) (actual time=0.058..710.780 rows=5010000 loops=1)
Heap Fetches: 582675
Planning Time: 0.596 ms
JIT:
Functions: 1
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 0.262 ms, Inlining 0.000 ms, Optimization 0.122 ms, Emission 2.295 ms, Total 2.679 ms
Execution Time: <strong>1249.391 ms</strong>
跨多个CPU运行DISTINCT是性能能力的一大进步。
但是请记住,当增加max_parallel_workers_per_gather的数量并接近硬件的限制时,性能下降的风险。
在正常情况下,查询计划器可能会决定使用索引而不是运行并行工作程序。
解决此问题的一种方法是考虑禁用运行时参数,例如enable_indexonlyscan和enable_indexscan。
最后,不要忘记运行EXPLAIN ANALYZE以了解发生了什么。
【PostgreSQL 】PostgreSQL 15对distinct的优化的更多相关文章
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...
- How to get the free disk space in PostgreSQL (PostgreSQL获取磁盘空间)
Get the current free disk space in PostgreSQL PostgreSQL获取磁盘空间 from eshizhan Here has a simple way t ...
- 【 PostgreSQL】十条实用数据库SQL优化建议
基于PostgreSQL,总结几条常用的查询操作的优化建议,部分也适用于Oracle等数据库. 1.选择合适的分布键 分布键选择不当会导致重分布.数据分布不均等,而数据分布不均会使SQL集中在一个se ...
- PostgreSQL 涉及复杂视图查询的优化案例
一.前言 对于含有union , group by 等的视图,我们称之为复杂视图. 这类的视图会影响优化器对于视图的提升,也就是视图无法与父查询进行合并,从而影响访问路径.连接方法.连接顺序等.本文通 ...
- 【PostgreSQL】 前缀模糊查询级优化
前匹配模糊 使用B-Tree来加速优化前匹配模糊查询 构造数据 新建一张商品表,插入一千万条数据. create table goods(id int, name varchar); insert i ...
- Google 发布的15个 Android 性能优化典范
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...
- [PostgreSQL]PostgreSQL数据类型格式化函数——字符串和数值间的转换
详情见官网:http://www.postgres.cn/docs/10/functions-formatting.html PostgreSQL中有以下格式化函数: 函数 返回类型 描述 例子 to ...
- 15、Jdbc的优化(BeanUtils组件)
Jdbc的优化! BeanUtils组件 自定义一个持久层的框架 DbUtils组件 案例优化 1. BeanUtils组件 1.1 简介 程序中对javabean的操作很频繁, 所以apach ...
- Java虚拟机15:运行期优化
前言 HotSpot采用的是解释器+编译器并存的架构,之前的这篇文章里面已经讲过了,本文只是把即时编译器这块再讲得具体一点而已.当然,其实本文的内容也没多大意义,90%都是概念上的东西,对于实际开发. ...
随机推荐
- CS基础课不完全自学指南
本文讲的是计算机学生怎么自学专业课,说长点就是该如何借助网络上已有的高质量学习资源(主要是公开课)来系统性的来点亮自己的CS技能树.这篇文章完全就是一篇自学性质的指南,需要对编程充满热情,起码觉得编程 ...
- JDBC往数据库传值中文乱码以及时区不一致解决
设置一下时区和编码就可以了 "jdbc:mysql://localhost:3306/jdbcprac?characterEncoding=UTF-8&&useSSL=fal ...
- 1.6 为什么要学Linux,它比Windows好在哪里?
早在 20 世纪 70 年代,UNIX 系统是开源而且免费的,但是在 1979 年时,AT&T 公司宣布了对 UNIX 系统的商业化计划,随之开源软件业转变成了版权式软件产业,源代码被当作商业 ...
- 『现学现忘』Git基础 — 22、Git中文件重命名
目录 1.用学过的命令进行文件重命名 2.使用git mv命令进行文件重命名 我们这篇文章来说说在Git中如何进行文件重命名. 提示一下,下面所说明的是对已经被Git管理的文件进行重命名,未被Git追 ...
- linux部署项目(前后端分离项目)
参考博客 技术栈 路飞学城部署 vue + nginx + uwsgi + django + mysql + redis(就是一个key - value型数据库,缓存型数据库,内存型数据库) 部署步骤 ...
- 如何形象简单地理解java中只有值传递,而没有引用传递?
首先,java中只有值传递,没有引用传递.可以说是"传递的引用(地址)",而不能说是"按引用传递". 按值传递意味着当将一个参数传递给一个函数时,函数接收的是原 ...
- 面试简历书写、Flask框架介绍与快速使用、Flask演示登录页面、用户信息页面案例
今日内容概要 面试简历编写 Flask框架介绍与安装 内容详细 1.面试简历编写 # 千万不要几个小时把简历凑出来 几天到一周 # 有没有面试机会,取决于简历写得怎么样 简历写好是第一步 # 投简历的 ...
- 2021夏季学期华清大学EE数算OJ2:难缠的店长
2021年夏季学期华清大学电子系数算oj2题解 某知名oier锐评蒟蒻的oj1题解: 话不多说,进入oj2题解: 难缠的oj 之 难缠的店长 当时读完我已经因为无良甲方的行为出离愤怒了!但是做题还是要 ...
- 标注工具doccano导出数据为空的解决办法
地址:https://github.com/taishan1994/doccano_export doccano_export 使用doccano标注工具同时导出实体和关系数据为空的解决办法.docc ...
- leetcode 643. Maximum Average Subarray I 子数组最大平均数 I
一.题目大意 https://leetcode.cn/problems/maximum-average-subarray-i/ 给你一个由 n 个元素组成的整数数组 nums 和一个整数 k . 请你 ...