联系管理员

开通文章发布权限

扫码 添加微信
微信图片
电话:15897897836 QQ:2106973531

PostgreSQL中的位图索引扫描(bitmap index scan)

摘自:https://www.cnblogs.com/wy123/p/13376991.html

从MySQL的MRR开始

开始之前,先从MySQL入手,看一下MySQL中的MRR机制原理,也就是Multi-Range Read。MySQL中在按照非聚集索引的范围查找且需要回表的情况下,比如下面的SQL,c2为非聚集索引。

select * from t where c2>100 and c2<200;

如果直接根据非聚集索引(二级索引)键中的聚集索引键去回表,会产生大量的随机性IO读取(图1)。
image
为了避免频繁的回表造成的随机IO,读取完非聚集索引上符合条件的key值之后,对key值对应的聚集索引键(图2的rowid)排序,然后根据排序后的聚集索引键顺序地回表,从而避免大量的随机性IO。
image
因为MySQL的Innodb表都是聚集表,那么图2中的rowid排序后,是顺序性的映射到聚集索引的page,从而避回表过程中的随机性IO。
以上原理清楚后,继续引申出来另外一个经典的问题:

MySQL中的Innodb总是聚集索引表,或者SqlServer中的聚集表,非聚集索引为什么要拿聚集索引键(而非物理地址)作为其行指针?

对于聚集表,表中数据的物理位置因为需要保证按聚集索引建有序,同时意味着其真正的物理的rowid可能会发生变化(比如聚集索引非线性写入的时候,会导致叶分裂,页分裂会导致原始记录的物理位置变化),此时非聚集索引的行指针rowid也要做修改,这样会导致聚集表中的数据发生物理位置变化的时候,非聚集索引也要做相应的变化,如果非聚集索引用对应的聚集索引键做指针的话,就不会发生该问题。

由以上两个问题做铺垫,来看看Postgresql中如何处理类似的问题。

Postgresql中的位图扫描(bitmap scan)

如果遇到类似于上述的查询(select * from t where c2>100 and c2<200;c2为非聚集索引的)情况下,查询结果是一个范围,那么Postgresql在回表的过程中,如何避免类似于上述图1中的随机性IO?

先弄清楚Postgresql的数据存储特点:

Postgresql表的数据都是以堆表(heap)的形式存储的,因此Postgresql中不存在所谓的聚集索引,同时意味着其记录在物理结构上可以是无序存储,不会产生所谓的页分裂(page split)。那么Postgresql中的行指针,这里称作rowid,正常情况是不会因为新数据的写入导致类似于MySQL或者sqlserver中的页拆分(page split)。

然后再说Postgresql的bitmap scan,bitmap scan的作用就是通过建立位图的方式,将回表过程中对标访问随机性IO的转换为顺行性行为,从而减少查询过程中IO的消耗。
参考这里:https://juejin.cn/post/6844903791347630087
image
先从一个非常简单的demo入手,如下查询,是一个典型的根据非聚集索引且需要回表的查询,满足以上的条件。可以看到在对idx_c5上执行了一个Bitmap Index Scan,由于Bitmap Index Scan记录的是符合条件的记录所在的block,而非记录的指针,通过类似于Oracle位图索引的检索模式进行数据的筛选,然后对这些位图信息指向的block排序后再进行回表(查询),Bitmap Index Scan之后有一个Recheck Cond是因为解析block的时候需要Recheck 。
image
最后,bitmap scan之后,对表的访问,总是通过bitmap Heap Scan完成。也就是执行计划的第一行。
这里的bitmap scan与上文中提到的MySQL中的MRR的思路算是一致的,都是通过中间一个缓存来避免随机性的IO访问,提升查询效率。
与基于聚集索引的总是从B+树的根节点通过二分法查找访问相比,对于postgresql中的这种直接基于物理Id的访问,从这一点上看,效率并不一定低。
bitmap scan的访问优化是基于代价考虑的,对于类似的查询,不总是一定走bitmap scan,如下,当访问的数据范围足够小的时候,可能不会走bitmap scan。
image
另外,bitmap scan的优化可以是基于不同字段或者不同筛选条件的,比如 where a>m and b>n(BitmapAndPath),亦或是where a>x or b>y(BitmapOrPath)这种访问方式,都可以通过bitmap scan来优化实现。
如果了解Oracle中的bitmap类似索引,加上这里的一个图例,应该比较容易理解bitmap生成机制
image

相关参数

正常情况下,是否用到bitmap scan优化,postgresql 优化器是可以选择出来一种最优的方式来执行的,但不保证总是可以生成最优化的执行计划,可以通过禁用bitmap scan或者 seqscan来尝试对比和调优。
任何优化都是一个系统工程,而不是一个单点工程,通过不同资源的消耗比例来提升整体性能,bitmap scan也并非完美无瑕,其优化理念是通过bitmap 的生成过程中增加内存和CPU字段消耗来减少IO消耗。
如果是高性能存储或者有充足的内存,并不一定总是发生物理IO,那么IO并不一定会是瓶颈,相反机械地去做bitmap的生成的话,反倒是一种浪费。
此时可以根据具体的IO能力,比如磁盘的随机读和顺序读代价参数,或者是禁用bitm scan等,来做整体上的优化方案。
image

 

相关文章

从安装PostgreSQL开始
通过以下步骤,你可以在 CentOS 7 上成功安装和配置 PostgreSQL 14。首先,设置 RPM 仓库并安装 PostgreSQL 14 服务器。然后,创建自定义数据存储目录并初始化数据库。接下来,修改启动脚本以使用自定义数据存储目录,并设置 PostgreSQL 监听所有 IP 地址。为了增强安全性,配置密码认证并修改 postgres 超级用户密码。最后,确保所有配置生效,重启 PostgreSQL 服务。通过这些步骤,你将拥有一个配置良好且安全的 PostgreSQL 数据库环境。如果在过程中遇到任何问题,请参考官方文档或寻求专业支持。
checkpoint是什么东西?一个位置?还是一个操作?
checkpoint是一个操作,执行这个操作的开始时刻,会记录当前开始时刻的 WAL 位置作为重做点,这个位置会被保存在文件中。 然后将该重做点之前所有 shared buffer 中的脏页均被刷入到存储。checkpoint又名检查点,一般checkpoint会将某个时间点之前的脏数据全部刷新到磁盘,以实现数据的一致性与完整性。
PostgreSQL 内参:深入解析运行原理【快照篇】
来源于灿哥的:《PostgreSQL 内参:深入解析运行原理》,非常好的一本书。
PG存在的级联删除(ON DELETE CASCADE)
在 PostgreSQL 中,如果你有两张表:用户表(users)和订单表(orders),并且用户表的主键是订单表的外键,那么你可以通过以下步骤来进行实验,删除订单表中的一条数据,然后删除用户表中的一条数据。

评论

快捷导航

把好文章收藏到微信

打开微信,扫码查看

关闭

还没有账号?立即注册