PostgreSQL17优化器改进(3)在使用包含操作符<@和@>时优化范围查询

PostgreSQL17优化器改进(3)在使用包含操作符<@和@>时优化范围查询

本文将介绍PostgreSQL 17服务端优化器在使用包含操作符<@和@>时优化范围查询。其实在在第一眼看到官网网站的对于该优化点的时候,可能是由于缺乏对于范围类型的认知,因此也不太清楚具体优化的场景,但是通过详细的阅读官网沟通邮件及官网文档,也基本搞明白了PostgreSQL17 的优化场景。下面是整理的功能测试用例及不支持的场景的测试用例。

创建测试用例需要的表

复制代码
CREATE TABLE rang_integer (num integer);
insert into rang_integer  select generate_series(-100000, 100000);
CREATE index idx_rang_integer ON rang_integer( num );
ANALYZE rang_integer;

PostgreSQL16.3中的执行计划

在PostgreSQL16.3中,测试用例将对比BETWEEN and语句和范围操作符@>、@< 的执行计划和执行用时。

复制代码
testdb=> EXPLAIN ANALYZE SELECT num FROM rang_integer WHERE num BETWEEN -10 AND 8;
                                                              QUERY PLAN                                                              
--------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using idx_rang_integer on rang_integer  (cost=0.42..4.80 rows=19 width=4) (actual time=0.470..0.475 rows=19 loops=1)
   Index Cond: ((num >= '-10'::integer) AND (num <= 8))
   Heap Fetches: 0
 Planning Time: 0.191 ms
 Execution Time: 0.502 ms
(5 rows)

Time: 1.721 ms
testdb=> 
testdb=> 
testdb=> EXPLAIN ANALYZE SELECT num FROM rang_integer WHERE num <@ int4range(-10, 8);
                                                  QUERY PLAN                                                   
---------------------------------------------------------------------------------------------------------------
 Seq Scan on rang_integer  (cost=0.00..3385.01 rows=1000 width=4) (actual time=17.626..36.529 rows=18 loops=1)
   Filter: (num <@ '[-10,8)'::int4range)
   Rows Removed by Filter: 199983
 Planning Time: 0.113 ms
 Execution Time: 36.552 ms
(5 rows)

Time: 37.285 ms

在PostgreSQL16.3版本中检查一个元素是否包含在一个范围中时,使用@>或<@操作符的性能比BETWEEN AND的查询性能都差且差距比较大;通过执行计划我们也可以看出,在使用范围操作符时,扫描方式使用的是Seq Scan on rang_integer ,未使用到范围过滤条件上的索引。

PostgreSQL17.0Beta 1中的执行计划

在PostgreSQL17中,同样测试用例将对比BETWEEN and语句和范围操作符@>、@< 的执行计划和执行用时。

复制代码
testdb=> EXPLAIN ANALYZE SELECT num FROM rang_integer WHERE num BETWEEN -10 AND 8;
                                                              QUERY PLAN                                                              
--------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using idx_rang_integer on rang_integer  (cost=0.42..4.84 rows=21 width=4) (actual time=0.281..0.286 rows=19 loops=1)
   Index Cond: ((num >= '-10'::integer) AND (num <= 8))
   Heap Fetches: 0
 Planning Time: 0.192 ms
 Execution Time: 0.315 ms
(5 rows)

Time: 1.205 ms
testdb=> 
testdb=> ^C
testdb=> EXPLAIN ANALYZE SELECT num FROM rang_integer WHERE num <@ int4range(-10, 8);
                                                              QUERY PLAN                                                              
--------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using idx_rang_integer on rang_integer  (cost=0.42..4.82 rows=20 width=4) (actual time=0.034..0.039 rows=18 loops=1)
   Index Cond: ((num >= '-10'::integer) AND (num < 8))
   Heap Fetches: 0
 Planning Time: 0.207 ms
 Execution Time: 0.061 ms
(5 rows)

Time: 0.794 ms

在PostgreSQL17版本中,优化范围值的查询后,通过对比 PostgreSQL16.3和PostgreSQL17的范围操作符查询,执行耗时由原来的37.285ms降低到0.794 ms,执行SQL的耗时大概提升了40倍多。我们再查看PostgreSQL17版本中的执行计划,发现在使用范围操作符时过滤数据时,已经用到之前新建的索引idx_rang_integer,因此查询才得到了提升。

PostgreSQL17.0Beta 1中不支持的场景

检查可变用例是否优化

这些用例是官网文档中提供的,通过下面的测试可知,对于值可变的情况,未进行优化

复制代码
testdb=> select now();
              now              
-------------------------------
 2024-06-11 17:06:07.074701+08
(1 row)

Time: 0.331 ms
testdb=> explain (verbose, costs off)
testdb-> select now() <@ tstzrange('2024-06-10 00:00', '2024-06-20 00:00');
                                                                 QUERY PLAN                                                                 
--------------------------------------------------------------------------------------------------------------------------------------------
 Result
   Output: ((now() >= '2024-06-10 00:00:00+08'::timestamp with time zone) AND (now() < '2024-06-20 00:00:00+08'::timestamp with time zone))
(2 rows)

Time: 0.610 ms
testdb=> explain (verbose, costs off)  -- unsafe!
testdb-> select clock_timestamp() <@ tstzrange('2024-06-10 00:00', '2024-06-20 00:00');
                                            QUERY PLAN                                             
---------------------------------------------------------------------------------------------------
 Result
   Output: (clock_timestamp() <@ '["2024-06-10 00:00:00+08","2024-06-20 00:00:00+08")'::tstzrange)
(2 rows)

Time: 0.532 ms
testdb=> explain (verbose, costs off)
testdb-> select clock_timestamp() <@ tstzrange('2024-01-20 00:00', NULL);
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Result
   Output: (clock_timestamp() >= '2024-01-20 00:00:00+08'::timestamp with time zone)
(2 rows)

Time: 0.714 ms

总结

在PostgreSQL 17中为范围操作符<@和@>添加优化器支持函数,这些支持函数将优化具有恒定范围值的表达式转换为对范围边界值的直接比较,其实就是启用了过滤条件上的索引。但是,有些情况也是不支持的,如果对可变的或代价高的元素表达式进行双重求值,则跳过该转换。

相关推荐
梦想不只是梦与想3 小时前
鸿蒙性能优化:启动速度
性能优化·harmonyos·启动速度
夜郎king5 小时前
SpringBoot+PostgreSQL + 硅基流动大模型从零搭建 Text-to-SQL 智能问答系统
spring boot·postgresql·text-to-sql·llm大模型
朱容zr3331335 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化
2501_942389555 小时前
Nifty IT指数的K线犹如断线的风筝
人工智能·postgresql·时序数据库·storm·tdengine
小孔龙6 小时前
RenderNode 与 DisplayList:Android 硬件加速的绘制记录与复用
android·性能优化
宁风NF6 小时前
JavaScript:内存、垃圾回收、性能优化
开发语言·前端·javascript·学习·性能优化·es6
Freak嵌入式1 天前
版本混乱 / 依赖缺失?uPyPi:MicroPython 版 PyPI,彻底解决库管理混乱
linux·服务器·数据库·单片机·嵌入式硬件·性能优化·依赖倒置原则
OK_boom1 天前
C# Dapper匹配postgresql的jsonb类型
开发语言·postgresql·c#
SelectDB技术团队1 天前
当 PostgreSQL 面临性能瓶颈:80TB 电商业务迁移至 Apache Doris 的实践思考
数据库·postgresql·apache
爱喝水的鱼丶1 天前
SAP-ABAP:SAP 实战笔记:BAPI_OUTB_DELIVERY_CONFIRM_DEC 详解——外向交货单过账的利器
运维·性能优化·sap·abap·经验交流