PostgreSQL增量排序使用场景

PostgreSQL增量排序使用场景

在上一篇技术文章PostgreSQL17优化器改进(8)支持GiST和SP-GiST索引进行增量排序中介绍了PostgreSQL17对于增量排序的新功能,但是对于增量排序,哪些场景可能会用到增量排序?这确实是一个不错的写作点,因此就有了我下面的这边功能测试文章。

准备测试用例及数据

这里的测试是使用官网测试用例表,数据可以从源码包中获取。

CREATE TABLE tenk1 (
	unique1		int4,
	unique2		int4,
	two			int4,
	four		int4,
	ten			int4,
	twenty		int4,
	hundred		int4,
	thousand	int4,
	twothousand	int4,
	fivethous	int4,
	tenthous	int4,
	odd			int4,
	even		int4,
	stringu1	name,
	stringu2	name,
	string4		name
);

导入测试数据

COPY tenk1 FROM '/data/tenk.data';
VACUUM ANALYZE tenk1;

在这里,为了能够使得测试用例使用到增量排序,只需要给four字段创建索引即可。

--创建索引
create index idx_tenk1_four on tenk1(four);

ORDER BY

常见的ORDER BY使用的场景有三个,除了ORDER BY单独使用外,也可以与limit或group by语法配合使用,在这些情况下,也是可以使用到增量排序的。

ORDER BY

测试的SQL语句

在该测试用例中,我们只指定ORDER BY子句。

explain select * from (select * from tenk1 order by four) t order by four, ten;
查看执行计划

在该执行计划中可见Incremental Sort节点,也就是使用到了增量排序。

testdb=# explain select * from (select * from tenk1 order by four) t order by four, ten;
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Incremental Sort  (cost=1256.73..1823.85 rows=10000 width=244)
   Sort Key: tenk1.four, tenk1.ten
   Presorted Key: tenk1.four
   ->  Sort  (cost=1109.39..1134.39 rows=10000 width=244)
         Sort Key: tenk1.four
         ->  Seq Scan on tenk1  (cost=0.00..445.00 rows=10000 width=244)
(6 rows)

如果在测试过程中,执行计划中未使用Incremental Sort,可能需要设置work_mem的值;另外在测试完成后,记得需要reset该参数,避免对后续的测试影响。

set work_mem to '2MB';
reset work_mem;

ORDER BY+LIMIT

测试的SQL语句

在该测试用例中,我们使用ORDER BY子句,并添加limit子句配合使用。

explain select * from (select * from tenk1 order by four) t order by four, ten limit 1;
查看执行计划

在该执行计划中可见Incremental Sort节点,也就是使用到了增量排序。

testdb=# explain select * from (select * from tenk1 order by four) t order by four, ten limit 1;
                                  QUERY PLAN                                   
-------------------------------------------------------------------------------
 Limit  (cost=1128.14..1128.15 rows=1 width=244)
   ->  Incremental Sort  (cost=1128.14..1309.47 rows=10000 width=244)
         Sort Key: tenk1.four, tenk1.ten
         Presorted Key: tenk1.four
         ->  Sort  (cost=1109.39..1134.39 rows=10000 width=244)
               Sort Key: tenk1.four
               ->  Seq Scan on tenk1  (cost=0.00..445.00 rows=10000 width=244)
(7 rows)

GROUP BY+ORDER BY

设置参数
--禁用enable_hashagg
set enable_hashagg =off;
测试的SQL语句

在该测试用例中,我们使用ORDER BY子句,并添加group by子句配合使用。

explain select four,ten,sum(two) from tenk1 group by four,ten order by four,ten,3;
查看执行计划

在该执行计划中可见Incremental Sort节点,也就是使用到了增量排序。

testdb=# explain select four,ten,sum(two) from tenk1 group by four,ten order by four,ten,3;
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Incremental Sort  (cost=1111.91..1211.59 rows=40 width=16)
   Sort Key: four, ten, (sum(two))
   Presorted Key: four, ten
   ->  GroupAggregate  (cost=1109.39..1209.79 rows=40 width=16)
         Group Key: four, ten
         ->  Sort  (cost=1109.39..1134.39 rows=10000 width=12)
               Sort Key: four, ten
               ->  Seq Scan on tenk1  (cost=0.00..445.00 rows=10000 width=12)
(8 rows)
重置参数

测试完成后,需要reset参数为默认值。

reset enable_hashagg;

窗口函数

测试的SQL语句

在该测试用例中,我们使用窗口函数并且使用ORDER BY子句指定排序。

explain select * from (
select unique1,unique2,two,four,ten,thousand,
row_number() over(partition by four order by ten) as firt_rn,
row_number() over(partition by four order by ten desc) as last_rn
from tenk1) emp where firt_rn=1 or last_rn=1;

查看执行计划

在该执行计划中可见Incremental Sort节点,也就是使用到了增量排序。

testdb=# explain select * from (
testdb(# select unique1,unique2,two,four,ten,thousand,
testdb(# row_number() over(partition by four order by ten) as firt_rn,
testdb(# row_number() over(partition by four order by ten desc) as last_rn
testdb(# from tenk1) emp where firt_rn=1 or last_rn=1;
                                        QUERY PLAN                                        
------------------------------------------------------------------------------------------
 Subquery Scan on emp  (cost=1300.58..2323.85 rows=100 width=40)
   Filter: ((emp.firt_rn = 1) OR (emp.last_rn = 1))
   ->  WindowAgg  (cost=1300.58..2173.85 rows=10000 width=40)
         ->  Incremental Sort  (cost=1300.50..1998.85 rows=10000 width=32)
               Sort Key: tenk1.four, tenk1.ten
               Presorted Key: tenk1.four
               ->  WindowAgg  (cost=1109.41..1309.39 rows=10000 width=32)
                     ->  Sort  (cost=1109.39..1134.39 rows=10000 width=24)
                           Sort Key: tenk1.four, tenk1.ten DESC
                           ->  Seq Scan on tenk1  (cost=0.00..445.00 rows=10000 width=24)
(10 rows)

DISTINCT

设置参数

--禁用enable_hashagg
set enable_hashagg =off;
SET enable_seqscan =off;

测试的SQL语句

在该测试用例中,我们只使用DISTINCT语法。DISTINCT是隐含需要排序的操作,可以不显示指定排序键。

EXPLAIN (costs off)
SELECT DISTINCT four, ten FROM tenk1;

查看执行计划

在该执行计划中可见Incremental Sort节点,也就是使用到了增量排序。

testdb=# EXPLAIN (costs off)
SELECT DISTINCT four, ten FROM tenk1;
                      QUERY PLAN                      
------------------------------------------------------
 Unique
   ->  Incremental Sort
         Sort Key: four, ten
         Presorted Key: four
         ->  Index Scan using idx_tenk1_four on tenk1
(5 rows)

重置参数

测试完成后,需要reset参数为默认值。

reset enable_hashagg;
reset enable_seqscan;

UNION

准备测试用例表及数据

create table t_union (a int, b int, c int);
insert into t_union select mod(i,10),mod(i,10),i from generate_series(1,10000) s(i);
create index on t_union (a);
analyze t_union;

设置参数

set enable_hashagg =off;

测试的SQL语句

在该测试用例中,我们只使用DISTINCT语法。DISTINCT是隐含需要排序的操作,可以不显示指定排序键。

explain (costs off) select * from t union select * from t order by 1,3;

查看执行计划

在该执行计划中可见Incremental Sort节点,也就是使用到了增量排序。

testdb=# explain (costs off) select * from t union select * from t order by 1,3;
                    QUERY PLAN                     
---------------------------------------------------
 Incremental Sort
   Sort Key: t.a, t.c
   Presorted Key: t.a
   ->  Unique
         ->  Merge Append
               Sort Key: t.a, t.b, t.c
               ->  Sort
                     Sort Key: t.a, t.b, t.c
                     ->  Seq Scan on t
               ->  Sort
                     Sort Key: t_1.a, t_1.b, t_1.c
                     ->  Seq Scan on t t_1
(12 rows)

重置参数

测试完成后,需要reset参数为默认值。

reset enable_hashagg;

总结

在这里我们测试PostgreSQL增量排序的ORDER BY、窗口函数、DISTINCT、UNION等场景,在这里我们只是验证在这些场景下是可以支持增量排序的,但是对于测试使用的SQL的语法是否规范不做要求。在日常开发过程中系统中,处理大量的数据集时,尽量配合limit子句使用,可以大幅提升SQL的查询性能。后续我将会用另外一篇文章来介绍增量排序的原理及其最佳实践。
– / END / –

可以通过下面的方式联系我

  • 微信公众号:@墨竹札记
  • 墨天轮:@墨竹
  • 微信:wshf395062788
  • PGFans:@墨竹

如果这篇文章为你带来了灵感或启发,就请帮忙点赞收藏转发;如果文章中不严谨或者错漏之处,请及时评论指正。非常感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨竹~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值