PostgreSQL 空间包含 OR 组合查询 、 IN 大量重复值 CASE 优化 - 消重、消bitmapOr、消filter

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

标签

PostgreSQL , 空间 or , in 重复值 , bitmap index scan , bitmapOr , filter , recheck


背景

简单的等值查询,空间包含查询,很容易想到使用索引加速。

但是当条件升级到IN,或者多个空间包含的OR查询时,数据库可能会选择多次索引扫描然后BitmapOr的方法,这种方法虽然用了索引,但是由于索引返回的是BLOCKID而不是CTID,所以会引入recheck。

《PostgreSQL bitmap scan的IO放大的原理解释和优化》

如果IN内数值,或者空间本身存在大量的重叠区间,那么性能会下降更严重。

postgres=# create table abc(id int primary key, info text);  
  
postgres=# insert into abc select generate_series(1,10000000), 'test';  
  
-- 查询100万个重复ID  
postgres=# do language plpgsql $$                                                                       
declare  
sql text;  
begin  
  select string_agg('1',',') into sql from generate_series(1,1000000);  
  sql := format('select * from abc where id in (%s);', sql);   
  raise notice '%', clock_timestamp();  
  execute sql;   
  raise notice '%', clock_timestamp();  
end;  
$$;  
NOTICE:  2018-06-22 02:35:54.731764+08  
NOTICE:  2018-06-22 02:35:55.841688+08  
DO  
Time: 1336.696 ms (00:01.337)  

实际场景中多个空间包含组合搜索还蛮常见:

查询所有连锁店覆盖的空间区域的数据,

查询多个空间圈选后包含的数据,

存在同样的问题,例如两个st_covers的or组合查询,变成了bitmap index scan

select * from xxx where st_covers(geo1,loc) or st_covers(geo2,loc) or .... st_covers(geo?,loc);
  
 Bitmap Heap Scan on xxx  (cost=8.84..13.37 rows=1 width=1194) (actual time=0.940..2.547 rows=215 loops=1)  
   Output: xxx  
   Recheck Cond: (('0103000020E610000001000000050000004607CD68194F5E40A30954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40A30954F216CA4240'::geography && xxx.location) OR ('0103000020E610000001000000050000004607CD68194F5E40250954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40250954F216CA4240'::geography && xxx.location))  
   Filter: ((('0103000020E610000001000000050000004607CD68194F5E40A30954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40A30954F216CA4240'::geography && xxx.location) AND _st_covers('0103000020E610000001000000050000004607CD68194F5E40A30954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40A30954F216CA4240'::geography, xxx.location)) OR (('0103000020E610000001000000050000004607CD68194F5E40250954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40250954F216CA4240'::geography && xxx.location) AND _st_covers('0103000020E610000001000000050000004607CD68194F5E40250954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40250954F216CA4240'::geography, xxx.location)))  
   Rows Removed by Filter: 18  
   Heap Blocks: exact=241  
   Buffers: shared hit=259  
   ->  BitmapOr  (cost=8.84..8.84 rows=1 width=0) (actual time=0.862..0.862 rows=0 loops=1)  
         Buffers: shared hit=18  
         ->  Bitmap Index Scan on xxx  (cost=0.00..4.42 rows=1 width=0) (actual time=0.465..0.465 rows=242 loops=1)  
               Index Cond: ('0103000020E610000001000000050000004607CD68194F5E40A30954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40A30954F216CA4240'::geography && xxx.location)  
               Buffers: shared hit=9  
         ->  Bitmap Index Scan on xxx  (cost=0.00..4.42 rows=1 width=0) (actual time=0.397..0.397 rows=242 loops=1)  
               Index Cond: ('0103000020E610000001000000050000004607CD68194F5E40250954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40250954F216CA4240'::geography && xxx.location)  
               Buffers: shared hit=9  
 Planning time: 0.719 ms  
 Execution time: 2.590 ms  
(17 rows)  

优化

数值IN大量重复值

1、SQL重写请参考:

《PostgreSQL in 与 = any 的SQL语法异同与性能优化》

2、客户端对输入条件去重,然后再拼接SQL进行输入

空间包含or组合查询

1、客户端对空间进行重叠处理去重,

2、然后根据空间BOX进行split,拆成多个空间对象,切割的目的是提高有效空间的占比。减少不规则空间对象使用GiST索引扫描时,BOUND BOX引入的无效记录的占比。提高效率。

3、将原来的OR改成,多个空间对象的包含查询,

4、union all组合多个查询。

select * from xxx where st_cover(geo1, loc)   
union all  
select * from xxx where st_cover(geo2, loc)   
union all  
...  
select * from xxx where st_cover(geo?, loc) ;  

执行计划会变成类似这样(注意下面演示的执行计划没有对空间去重(只是演示问题,不是真实问题),你需要关注的是空间去重后,recheck没有了,bitmap scan没有了,只有append, INDEX SCAN。真实情况下按bound box切割时多个index scan扫描的BLOCK是完全隔离的,不会产生冗余扫描。)

同时,原始的查询条件如果有100个OR,实际上在空间处理后换成union all的查询可能没有100个UNION ALL,根据实际的空间SPLIT情况来定。

 Append  (cost=0.41..17.40 rows=2 width=1178) (actual time=0.126..3.267 rows=430 loops=1)
   Buffers: shared hit=500
   ->  Index Scan using xxx on xxx.xxx  (cost=0.41..8.69 rows=1 width=1194) (actual time=0.126..1.821 rows=215 loops=1)
         Output: xxx
         Index Cond: ('0103000020E610000001000000050000004607CD68194F5E40A30954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40A30954F216CA4240'::geography && xxx.location)
         Filter: _st_covers('0103000020E610000001000000050000004607CD68194F5E40A30954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40A30954F216CA4240'::geography, xxx.location)
         Rows Removed by Filter: 18
         Buffers: shared hit=250
   ->  Index Scan using xxx on xxx.xxx xxx_1  (cost=0.41..8.69 rows=1 width=1194) (actual time=0.101..1.402 rows=215 loops=1)
         Output: xxx
         Index Cond: ('0103000020E610000001000000050000004607CD68194F5E40250954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40250954F216CA4240'::geography && xxx_1.location)
         Filter: _st_covers('0103000020E610000001000000050000004607CD68194F5E40250954F216CA42404607CD68194F5E4017898ACF2AC742401DBB4CC022505E4017898ACF2AC742401DBB4CC022505E40A30954F216CA42404607CD68194F5E40250954F216CA4240'::geography, xxx_1.location)
         Rows Removed by Filter: 18
         Buffers: shared hit=250

如果客户端的计算都可以在PostGIS中实现,那么也可以交给PG来处理(引入一些空间计算的开销),但是数据库数据扫描与RECHECK,FILTER的开销则降低了。

在数据库端实现的优化例子:

《PostgreSQL 空间切割(st_split, ST_Subdivide)功能扩展 - 空间对象网格化 (多边形GiST优化)》

《PostgreSQL 空间st_contains,st_within空间包含搜索优化 - 降IO和降CPU(bound box) (多边形GiST优化)》

小结

本例的优化思路,通过对条件本身去重,降低扫描成本,降低recheck成本。

在处理空间查询时,对多个OR条件的空间对象进行组合,空间交叠后,按BOX切割成多个空间对象,使用UNION ALL组合查询,降低扫描成本。

参考

《PostgreSQL 空间切割(st_split, ST_Subdivide)功能扩展 - 空间对象网格化 (多边形GiST优化)》

《PostgreSQL 空间st_contains,st_within空间包含搜索优化 - 降IO和降CPU(bound box) (多边形GiST优化)》

《PostgreSQL in 与 = any 的SQL语法异同与性能优化》

《HTAP数据库 PostgreSQL 场景与性能测试之 25 - (OLTP) IN , EXISTS 查询》

《聊一下PostgreSQL优化器 - in里面有重复值时PostgreSQL如何处理?》

https://postgis.net/docs/ST_Covers.html

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
28天前
|
关系型数据库 分布式数据库 数据库
PolarDB常见问题之加了索引但是查询没有使用如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
17天前
|
存储 JSON 关系型数据库
PostgreSQL Json应用场景介绍和Shared Detoast优化
PostgreSQL Json应用场景介绍和Shared Detoast优化
|
2月前
|
SQL 关系型数据库 分布式数据库
在PolarDB for PostgreSQL中,你可以使用LIKE运算符来实现类似的查询功能,而不是使用IF函数
在PolarDB for PostgreSQL中,你可以使用LIKE运算符来实现类似的查询功能,而不是使用IF函数
42 7
|
2月前
|
存储 关系型数据库 分布式数据库
PolarDB for PostgreSQL查询问题之条件查询失败如何解决
PolarDB for PostgreSQL是基于PostgreSQL开发的一款云原生关系型数据库服务,它提供了高性能、高可用性和弹性扩展的特性;本合集将围绕PolarDB(pg)的部署、管理和优化提供指导,以及常见问题的排查和解决办法。
|
3月前
|
存储 关系型数据库 分布式数据库
阿里云PolarDB解决乐麦多源数据存储性能问题
乐麦通过使用PolarDB数据库,使整个系统之间的数据查询分析更加高效
390 3
|
3月前
|
弹性计算 关系型数据库 数据库
开源PostgreSQL在倚天ECS上的最佳优化实践
本文基于倚天ECS硬件平台,以自顶向下的方式从上层应用、到基础软件,再到底层芯片硬件,通过应用与芯片的硬件特性的亲和性分析,实现PostgreSQL与倚天芯片软硬协同的深度优化,充分使能倚天硬件性能,帮助开源PostgreSQL应用实现性能提升。
|
3月前
|
SQL 关系型数据库 分布式数据库
在PolarDB for PostgreSQL中,你可以使用LIKE运算符来实现类似的查询功能
在PolarDB for PostgreSQL中,你可以使用LIKE运算符来实现类似的查询功能【1月更文挑战第13天】【1月更文挑战第65篇】
30 2
|
21天前
|
关系型数据库 分布式数据库 数据库
成都晨云信息技术完成阿里云PolarDB数据库产品生态集成认证
近日,成都晨云信息技术有限责任公司(以下简称晨云信息)与阿里云PolarDB PostgreSQL版数据库产品展开产品集成认证。测试结果表明,晨云信息旗下晨云-站群管理系统(V1.0)与阿里云以下产品:开源云原生数据库PolarDB PostgreSQL版(V11),完全满足产品兼容认证要求,兼容性良好,系统运行稳定。
|
28天前
|
关系型数据库 分布式数据库 数据库
PolarDB常见问题之数据库不能自己减少节点如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
28天前
|
缓存 关系型数据库 分布式数据库
PolarDB常见问题之数据库cpu突然飙高如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。

相关产品

  • 云原生数据库 PolarDB