Postgresql中的位图扫描(bitmap scan)「终于解决」

Postgresql中的位图扫描(bitmap scan)「终于解决」从MySQL的MRR开始 开始之前,先从MySQL入手,看一下MySQL中的MRR机制原理,也就是Multi-Range Read。MySQL中在按照非聚集索引的范围查找且需要回表的情况下,比如sel

Postgresql中的位图扫描(bitmap scan)

 

从MySQL的MRR开始

开始之前,先从MySQL入手,看一下MySQL中的MRR机制原理,也就是Multi-Range Read。
MySQL中在按照非聚集索引的范围查找且需要回表的情况下,比如select * from t where c2>100 and c2<200;c2为非聚集索引。
如果直接根据非聚集索引(二级索引)键中的聚集索引键去回表,会产生大量的随机性IO读取(图1)。
为了避免频繁的回表造成的随机IO,读取完非聚集索引上符合条件的key值之后,对key值对应的聚集索引键(图2的rowid)排序,然后根据排序后的聚集索引键顺序地回表,从而避免大量的随机性IO。
因为MySQL的Innodb表都是聚集表,那么图2中的rowid排序后,是顺序性的映射到聚集索引的page,从而避回表过程中的随机性IO。

Postgresql中的位图扫描(bitmap scan)「终于解决」(图1) Postgresql中的位图扫描(bitmap scan)「终于解决」(图2)

以上原理清楚后,继续引申出来另外一个经典的问题:
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的消耗。
先从一个非常简单的demo入手,如下查询,是一个典型的根据非聚集索引且需要回表的查询,满足以上的条件。
可以看到在对idx_c5上执行了一个Bitmap Index Scan,由于Bitmap Index Scan记录的是符合条件的记录所在的block,而非记录的指针,然后对这些block排序后再进行回表,Bitmap Index Scan之后有一个Recheck Cond是因为解析block的时候需要Recheck 。
参考这里:The bitmap is one bit per heap page. The bitmap index scan sets the bits based on the heap page address that the index entry points to.
Postgresql中的位图扫描(bitmap scan)「终于解决」
最后,bitmap scan之后,对表的访问,总是通过bitmap Heap Scan完成。也就是执行计划的第一行。
这里的bitmap scan与上文中提到的MySQL中的MRR的思路算是一致的,都是通过中间一个缓存来避免随机性的IO访问,提升查询效率。
与基于聚集索引的总是从B+树的根节点通过二分法查找访问相比,对于postgresql中的这种直接基于物理Id的访问,从这一点上看,效率并不一定低。

bitmap scan的访问优化是基于代价考虑的,对于类似的查询,不总是一定走bitmap scan,如下,当访问的数据范围足够小的时候,可能不会走bitmap scan。
Postgresql中的位图扫描(bitmap scan)「终于解决」
另外,bitmap scan的优化可以是基于不同字段或者不同筛选条件的,比如 where a>m and b>n(BitmapAndPath),亦或是where a>x or b>y(BitmapOrPath)这种访问方式,都可以通过bitmap scan来优化实现。

只不过笔者这里还有一个问题,因为postgresql中对行的update都是直接删除原始记录,然后新写入一条记录来实现的,只要这条记录的物理页面不变,那么非聚集索引的行指针就不变,如果这个记录的物理页面发生了变话,是不是索引的指针也会发生变化?

相关参数

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

参考
https://dba.stackexchange.com/questions/119386/understanding-bitmap-heap-scan-and-bitmap-index-scan
https://blog.csdn.net/weixin_33672400/article/details/89734245

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/7090.html

(0)
上一篇 2023-03-27
下一篇 2023-03-27

相关推荐

  • Python代码行数统计

    Python代码行数统计作为一名Python工程师,我们经常需要对自己的代码进行统计和分析,以提高开发和维护效率。而其中一个重要的统计指标就是代码行数。本文将从多个方面对统计Python代码行数做详细的阐述。

    2024-05-05
    69
  • Python中list的字符串切割技巧

    Python中list的字符串切割技巧split()函数是Python中常用的字符串操作函数,可以将一个字符串按照指定符号分割成多个子字符串,并返回一个包含所有子字符串的列表(list)。下面是一个简单的示例:

    2024-04-03
    77
  • oracle数据库12c安装教程_anaconda安装教程

    oracle数据库12c安装教程_anaconda安装教程一、下载地址 Oracle Database 官方下载地址:https://www.oracle.com/database/technologies/oracle-database-software-

    2023-02-21
    151
  • 1.5 HDFS分布式文件系统-hadoop「建议收藏」

    1.5 HDFS分布式文件系统-hadoop「建议收藏」1.5 HDFS分布式文件系统 1.5.1 HDFS 简介 HDFS(全称:Hadoop Distribute File System,Hadoop 分布式文件系统)是 Hadoop 核心组成,是分布

    2023-06-19
    139
  • python对数据库mysql的操作(增删改查)「终于解决」

    python对数据库mysql的操作(增删改查)「终于解决」 #coding=utf-8import pymysql# #查询# def connMySQL():# try:# conn=pymysql.connect(‘localhost’,’roo…

    2023-03-24
    162
  • 基于 Apache Hudi 极致查询优化的探索实践

    基于 Apache Hudi 极致查询优化的探索实践摘要:本文主要介绍 Presto 如何更好的利用 Hudi 的数据布局、索引信息来加速点查性能。 本文分享自华为云社区《华为云基于 Apache Hudi 极致查询优化的探索实践!》,作者:FI_me

    2023-06-07
    149
  • MySQL学习笔记(13):锁和事务「建议收藏」

    MySQL学习笔记(13):锁和事务「建议收藏」本文更新于2019-09-22,使用MySQL 5.7,操作系统为Deepin 15.4。 锁 锁概述 MyISAM和MEMORY存储引擎使用表级锁。BDB存储引擎进使用页级锁,但也支持表级锁。Inn

    2023-03-19
    142
  • 以fillchar为中心写一个标题

    以fillchar为中心写一个标题随着数字化时代的到来,文本处理成为了人们生活中不可或缺的一部分。填充字符串是文本处理中常用的功能,用于在文本中添加一些特定字符(通常是空格)以对齐文本结构。fillchar作为填充字符串的一种常用方式,其使用广泛,使用fillchar在文本中添加一些特定字符(通常是空格),以对齐文本结构,提高文本的可读性和美观程度。本篇文章将从使用fillchar的基本方法、fillchar与字符串对齐、填充长整型、取反填充字符串四个方面进行详细的阐述。希望通过本文的讲解,能够帮助读者更灵活地使用fillchar,提高文本处理能力。

    2024-05-04
    58

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注