博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GreenPlum的Bitmap Heap Scan和 Bitmap Index Scan
阅读量:3522 次
发布时间:2019-05-20

本文共 3624 字,大约阅读时间需要 12 分钟。

一、Bitmap Heap Scan/  Bitmap Index Scan

在查看GP的执行计划会看到Bitmap Heap Scan/  Bitmap Index Scan/Bitmap Or/Bitmap And.这些关键字是什么意思呢?

               Bitmap Index Scan/Bitmap Or/Bitmap And ->  Bitmap Heap Scan。 前者的cost最红会汇总到后面的Cost。

如下图:

定义

A plain indexscan fetches one tuple-pointer at a time from the index,and immediately visits that tuple in the table. A bitmap scan fetches all the tuple-pointers from the index in one go, sorts them using an in-memory "bitmap" data structure, and then visits the table tuples in physical tuple-location order. The bitmap scan improves locality of reference to the table at the cost of more bookkeeping overhead to manage the "bitmap" data structure --- and at the cost that the data is no longer retrieved in index order, which doesn't matter for your query but would matter if you said ORDER BY.

A bitmapped index scan works in two stages. First the index or indexes are scanned to create a bitmap representing matching tuple.

这段解释是tom lane在postgres邮件组中的回答,我觉得是比较权威而且通俗易懂的解释。

核心是传统的index scan每次从索引中去取一个tuple的指针,然后立马去表中取数据,每一次会造成一次随机io。如果数据量较多的情况下,会比较低效。而bitmap scan一次性将符合条件的tuple-pointers全部取出来,然后在内存中进行地址排序,然后去取出数据,这时的读取数据由于进行的地址排序,读取时就变成了顺序的读。其实就是一个随机读转化为顺序读取的过程,但是取出的数据由于进行了地址的排序,就没有顺序。同时,对于limit这种sql,bitmap index scan这种就不适合,因为它一次会取出所有数据。(原因是Bitmap Index Scan需要完成Index Rows的扫描在内存中建立Bitmap后才能访问表数据,而Index Scan或者Seq Scan则没有预先步骤直接扫描一行输出一行,因此Bitmap Index Scan在存在limit子句时性能可能会较差)

Index Scan 和bitMap Index Scan的比较?

参考:

        

什么时候会发生Bitmap Heap Scan?

当某一字段的重复值很多时,执行计划会走此种索引。这只是从宏观上从经验上。具体可以参考上面的第一篇文章,从微观上详细阐述了为何会发生bitmap index scan,以及为何会发生Bitmap Heap Scan,以及Recheck Con的使用情景。

大致意思是:如果index scan扫描的数据过多,计划器会选择透过bitmap scan 扫描很多tuple。如何决定是要透过index scan 还是bitmap scan执行呢?计划期会根据 i/o ,collection(物理行和逻辑行的相关性),等列的局部属性都会影响。当使用bitmap每次扫描到的tuple足够多时,(个人理解:计划期认为扫描的tuple足够占据一个page时)就会发生BitMap Heap Scan。Recheck Cond这时候就发生了,用来检查所选条件的数据是否都在这个page上,执行计划难免不准,double check毋庸置疑。当发生bitmap lossy的时候,(个人理解就是标记的此页有不满足条件的tuple)才会真正发生recheck。

在bitmap lossy情况中,我们只记住哪些page包含匹配的tuple,而不是逐个记住每个tuple。当这种情况发生时,表访问阶段必须检查page上的每个tuple,并真正的发生recheck cond,以此来确认要返回哪些tuple。

需要注意的是: postger的index扫描很特殊,虽然是一行一行的扫描,但可以选择不立即返回,它可以记住match到哪一个page,当完成对index的扫描。的时候再从磁盘刷新出来,这样便只读取具有match的tuple对应的page一次。减少了页面的读取次数,其实最近从硬盘刷新出来的资料会放在buffer中,如果在未刷回硬盘的时候再读取match到的page时速度应该还是可以的。

请看下例

explain select relkind,* from pg_class_temp where relkind = 'r'--pg_class中的relkind字段,重复值很多,在这个字段上建立索引--relkind是什么意思呢? --1、来判断一个对象是表还是视图还是索引......。--2、 r =普通表,i = 索引,S =序列,v = 视图, c =复合类型,s = 特殊,t =TOAST表create index pg_class_relkind_idx on pg_class_temp(relkind);--enable_seqscan禁止顺序扫描,确保执行计划是通过pg_class_relkind_idx来查询数据set optimizer=off

执行计划如下所示。

此处需要注意的是要关闭seqScan。否则数据量较小的情况下,执行器会直接seqScan。为了让测试结果更准确优化器也最好关掉。

以下是占用GP master CPU较高的sql之一对应的exlpain。可以看,此段sqlslice2的work_mem大小约为313M。而GP的设定是32MB。所以说此段sql中slice 的recheck cond是真实发生的,这验证了前文所述。如何优化?

Slice statistics:  (slice0)    Executor memory: 21780K bytes.  (slice1)    Executor memory: 3654123K bytes avg x 48 workers, 3869945K bytes max (seg38).  Work_mem: 32776K bytes max.Statement statistics:  Memory used: 128000K bytesSettings:  enable_bitmapscan=on; enable_seqscan=off; optimizer=offOptimizer status: legacy query optimizerTotal runtime: 294592.942 ms

在postgresql 9.4版本的执行计划中已经可以看到具体的bitmap lossy。例如

Bitmap Heap Scan on aa  (cost=107.68..4818.05 rows=5000 width=4) (actual time=27.629..213.606 rows=100001 loops=1)  Recheck Cond: ((a >= 100000) AND (a <= 200000))  Rows Removed by Index Recheck: 758222  Heap Blocks: exact=693 lossy=3732  ->  Bitmap Index Scan on aai  (cost=0.00..106.43 rows=5000 width=0) (actual time=27.265..27.265 rows=100001 loops=1)        Index Cond: ((a >= 100000) AND (a <= 200000))

源码级别的探讨参见:

 

转载地址:http://njhqj.baihongyu.com/

你可能感兴趣的文章
[LeetCode javaScript] 75. 颜色分类
查看>>
[LeetCode javaScript] 179. 最大数
查看>>
[LeetCode javaScript] 56. 合并区间
查看>>
[LeetCode javaScript] 190. 颠倒二进制位
查看>>
[LeetCode javaScript] 521. 最长特殊序列 Ⅰ
查看>>
[LeetCode javaScript] 806. 写字符串需要的行数
查看>>
[LeetCode javaScript] 868. 二进制间距
查看>>
[LeetCode javaScript] 824. 山羊拉丁文
查看>>
[LeetCode javaScript] 463. 岛屿的周长
查看>>
[LeetCode javaScript] 107. 二叉树的层次遍历 II
查看>>
[LeetCode javaScript] 637. 二叉树的层平均值
查看>>
[LeetCode javaScript] 1. 两数之和
查看>>
[LeetCode javaScript] 14. 最长公共前缀
查看>>
[LeetCode javaScript] 26. 删除排序数组中的重复项
查看>>
[LeetCode javaScript] 8. 字符串转换整数 (atoi)
查看>>
[LeetCode javaScript] 28. 实现strStr()
查看>>
cv2.error: OpenCV(3.4.2) c:\projects\opencv-python\opencv\modules\imgproc\src\color.hpp:25
查看>>
前端网页学习7(css背景属性)
查看>>
前端网页学习8(css三大特性:层叠性,继承性,优先级)
查看>>
前端网页学习9(css盒子)
查看>>