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

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介:

标签

PostgreSQL , bitmap scan , io 放大 , cpu 放大 , recheck , 数据聚集


背景

PostgreSQL 支持9种索引接口:

《PostgreSQL 9种索引的原理和应用场景》

每一种索引的结构,适合的数据类型,适合的查询场景都不一样。

对于多值类型(例如 K-V,数组、全文检索 类型),我们可以选择GIN倒排索引接口,GIN使用的扫描方法是bitmap scan的扫描方法。

实际上PostgreSQL常用的数据扫描方法包括:

  • seq scan,全表扫描

  • index scan,索引扫描(需要回表)

  • index only scan,索引扫描(通过VM减少回表,大多数情况下,不需要回表)

  • bitmap scan,先扫索引,然后按HEAP BLOCK ID扫描HEAP BLOCK。输出整个数据块的数据,因此需要recheck。

bitmap scan的特性,决定了它可能存在放大(因为一个BLOCK里面哪怕只有一条记录是复合条件的,也会返回整个BLOCK)。

bitmap scan IO,CPU放大例子

1、新建测试表

create table test(id int, arr int[]);  

2、写入测试数据

create or replace function gen_arr(int,int) returns int[] as $$  
  select array(select ($1*random())::int from generate_series(1,$2));  
$$ language sql strict;  
  
postgres=# select gen_arr(100,10);  
            gen_arr              
-------------------------------  
 {5,71,91,23,95,81,98,12,33,2}  
(1 row)  
  
insert into test select id, gen_arr(1000, 10) from generate_series(1,1000000) t(id);  

3、创建索引

create index idx_test_1 on test using gin (arr);  

4、查询,分析

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from test where arr && array[1,2,3];  
                                                          QUERY PLAN                                                             
-------------------------------------------------------------------------------------------------------------------------------  
 Bitmap Heap Scan on public.test  (cost=808.96..13148.92 rows=23402 width=36) (actual time=14.295..52.321 rows=29605 loops=1)  
   Output: id, arr  
   Recheck Cond: (test.arr && '{1,2,3}'::integer[])  
   Heap Blocks: exact=11240  
   Buffers: shared hit=11764  
   ->  Bitmap Index Scan on idx_test_1  (cost=0.00..803.11 rows=23402 width=0) (actual time=12.816..12.816 rows=29605 loops=1)  
         Index Cond: (test.arr && '{1,2,3}'::integer[])  
         Buffers: shared hit=524  
 Planning time: 0.314 ms  
 Execution time: 54.896 ms  
(10 rows)  

包含1或2或3的数据,总共2.9万条,搜索了11240个HEAP BLOCK。

那么我们看看一个BLOCK可以存储多少数据?

postgres=# analyze test;  
ANALYZE  
postgres=# select reltuples/relpages from pg_class where relname='test';  
     ?column?       
------------------  
 80.9978940547546  
(1 row)  

可以存下81条,意味着实际上29605条记录应该只需要365个数据块就可以放下。

但是由于这些目标记录没有密集存储,导致了IO的放大。

那么如何解决这个问题呢?

bitmap scan IO,cpu放大问题优化

1、聚集存储

实现方法很多,这里有一些例子:

《PostgreSQL 黑科技 - 空间聚集存储, 内窥GIN, GiST, SP-GiST索引》

《PostgreSQL GIN 单列聚集索引 应用》

《PostgreSQL 聚集存储 与 BRIN索引 - 高并发行为、轨迹类大吞吐数据查询场景解说》

《K-Means 数据聚集算法》

我们可以看看聚集带来的效果:

-- 重组数据  
postgres=# with tmp as (delete from test where ctid = any(array(select ctid from test where arr && array[1,2,3])) returning *) insert into test select * from tmp;  
INSERT 0 29605  
  
-- 再次查询  
postgres=# vacuum test;  
VACUUM  
postgres=# explain (analyze,verbose,timing,costs,buffers) select * from test where arr && array[1,2,3];  
                                                         QUERY PLAN                                                            
-----------------------------------------------------------------------------------------------------------------------------  
 Bitmap Heap Scan on public.test  (cost=247.16..13321.03 rows=28950 width=65) (actual time=3.459..8.248 rows=29605 loops=1)  
   Output: id, arr  
   Recheck Cond: (test.arr && '{1,2,3}'::integer[])  
   Heap Blocks: exact=367  
   Buffers: shared hit=389  
   ->  Bitmap Index Scan on idx_test_1  (cost=0.00..239.92 rows=28950 width=0) (actual time=3.411..3.411 rows=29605 loops=1)  
         Index Cond: (test.arr && '{1,2,3}'::integer[])  
         Buffers: shared hit=22  
 Planning time: 0.145 ms  
 Execution time: 10.991 ms  
(10 rows)  

现在只访问了367个HEAP数据块。完全避免了IO放大的问题。

实际情况,可以根据业务喜好来聚集。

参考

《PostgreSQL 黑科技 - 空间聚集存储, 内窥GIN, GiST, SP-GiST索引》

《PostgreSQL GIN 单列聚集索引 应用》

《PostgreSQL 聚集存储 与 BRIN索引 - 高并发行为、轨迹类大吞吐数据查询场景解说》

《K-Means 数据聚集算法》

《PostgreSQL 9种索引的原理和应用场景》

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
监控 关系型数据库 数据库
PostgreSQL的索引优化策略?
【8月更文挑战第26天】PostgreSQL的索引优化策略?
601 1
|
10月前
|
固态存储 关系型数据库 数据库
从Explain到执行:手把手优化PostgreSQL慢查询的5个关键步骤
本文深入探讨PostgreSQL查询优化的系统性方法,结合15年数据库优化经验,通过真实生产案例剖析慢查询问题。内容涵盖五大关键步骤:解读EXPLAIN计划、识别性能瓶颈、索引优化策略、查询重写与结构调整以及系统级优化配置。文章详细分析了慢查询对资源、硬件成本及业务的影响,并提供从诊断到根治的全流程解决方案。同时,介绍了索引类型选择、分区表设计、物化视图应用等高级技巧,帮助读者构建持续优化机制,显著提升数据库性能。最终总结出优化大师的思维框架,强调数据驱动决策与预防性优化文化,助力优雅设计取代复杂补救,实现数据库性能质的飞跃。
1561 0
|
存储 监控 关系型数据库
MySQL 参数innodb_read_io_threads
`innodb_read_io_threads` 是 MySQL 数据库中 InnoDB 存储引擎的一个配置参数,它用于指定后台线程池中用于处理读取 I/O 请求的线程数量。InnoDB 存储引擎负责管理数据库的物理存储和检索,是 MySQL 最常用的存储引擎之一。 ### 参数说明 - **名称**: `innodb_read_io_threads` - **默认值**: 4 - **范围**: 1 到 64 - **动态修改**: 不能动态修改(需要重启服务器) - **适用版本**: MySQL 5.6 及以上版本 ### 作用 `innodb_read_io_threads`
1620 1
|
JSON 关系型数据库 PostgreSQL
PostgreSQL 9种索引的原理和应用场景
PostgreSQL 支持九种主要索引类型,包括 B-Tree、Hash、GiST、SP-GiST、GIN、BRIN、Bitmap、Partial 和 Unique 索引。每种索引适用于不同场景,如 B-Tree 适合范围查询和排序,Hash 仅用于等值查询,GiST 支持全文搜索和几何数据查询,GIN 适用于多值列和 JSON 数据,BRIN 适合非常大的表,Bitmap 适用于低基数列,Partial 只对部分数据创建索引,Unique 确保列值唯一。
1323 15
|
关系型数据库 MySQL Docker
docker pull mysql:8.0.26提示Error response from daemon: Get “https://registry-1.docker.io/v2/“: EOF错误
docker pull mysql:8.0.26提示Error response from daemon: Get “https://registry-1.docker.io/v2/“: EOF错误
4743 9
|
关系型数据库 MySQL Linux
升级到MySQL 8.4,MySQL启动报错:io_setup() failed with EAGAIN
当MySQL 8.4启动时报错“io_setup() failed with EAGAIN”时,通常是由于系统AIO资源不足所致。通过增加AIO上下文数量、调整MySQL配置、优化系统资源或升级内核版本,可以有效解决这一问题。上述解决方案详细且实用,能够帮助管理员快速定位并处理此类问题,确保数据库系统的正常运行。
530 9
|
人工智能 Cloud Native Java
云原生技术深度解析:从IO优化到AI处理
【10月更文挑战第24天】在当今数字化时代,云计算已经成为企业IT架构的核心。云原生作为云计算的最新演进形态,旨在通过一系列先进的技术和实践,帮助企业构建高效、弹性、可观测的应用系统。本文将从IO优化、key问题解决、多线程意义以及AI处理等多个维度,深入探讨云原生技术的内涵与外延,并结合Java和AI技术给出相应的示例。
413 1
|
缓存 关系型数据库 数据库
如何优化 PostgreSQL 数据库性能?
如何优化 PostgreSQL 数据库性能?
766 2
|
监控 关系型数据库 数据库
如何优化PostgreSQL的性能?
【8月更文挑战第4天】如何优化PostgreSQL的性能?
887 7
|
缓存 Linux 调度
[kvm]硬盘IO优化
[kvm]硬盘IO优化
396 2

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 推荐镜像

    更多