首页 » PostgreSQL/GaussDB » PostgreSQL/openGauss explain解析(五): Bitmap Index Scan 和 Heap Blocks、Recheck Cond

PostgreSQL/openGauss explain解析(五): Bitmap Index Scan 和 Heap Blocks、Recheck Cond

在前面几个index only scan测试中如果没有改random_page_cost值,相信应该看到过Bitmap Index Scan 的执行计划,也可以使用参数enable_bitmapscan允许或禁用位图扫描,在oracle中CBO当1个表上两个索引(B树索引)先组合”bitmap and “再回表过滤数据,参数_b_tree_bitmap_plans可以禁用该形为,通常出现这种性能不值考虑组合索引,在PostgreSQL中同样biatmap scan可以用于单表多索引的联合过滤,同时一个索引也可能会出这种形为。

测试 opengauss 5.0

openGauss=#  create table testc(id int,name varchar(20),addr  varchar(3000),otype char(1));
CREATE TABLE
openGauss=# insert into testc select x,'anbob'||x,rpad('x',2000,'x'),'t' from generate_series(1,10000) as x;
INSERT 0 10000
openGauss=# insert into testc values(0,null,null,'i');
INSERT 0 1
openGauss=# select otype,count(*) from testc group by otype;
 otype | count
-------+-------
 i     |     1
 t     | 10000
(2 rows)

openGauss=# create index idx_testc_p_id on testc(id) where otype='i';
CREATE INDEX
openGauss=# vacuum testc;
VACUUM
openGauss=# explain analyze select otype from testc where otype='i';
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on testc  (cost=4.27..91.66 rows=50 width=8) (actual time=0.079..0.080 rows=1 loops=1)
   Recheck Cond: (otype = 'i'::bpchar)
   Heap Blocks: exact=1
   ->  Bitmap Index Scan on idx_testc_p_id  (cost=0.00..4.25 rows=50 width=0) (actual time=0.071..0.071 rows=1 loops=1)
 Total runtime: 0.205 ms
(5 rows)

Note:
如果我们本来以为会index only scan,结果是biatmap index/heap scan

Index scan是从B树索引键和表page地址指针,从表heap page获取其他信息,顺序对于每个索引键都是index page到heap page,再Index page 到heap page… 甚至存在多次Index page和heap page多次相同,产生大量的随即page访问,提升了随机I/O的代价,这也是为什么我们降低了random page cost原因。

Seq scan又是heap page按顺序遍历所有heap Page,虽然是顺序IO,但全表扫I/O代价也不少, 那有没有两者折中的办法? 所以有了Bitmap scan.

 

Bitmaps 可以存储row的bitmap,如果bitmap size变得太大而无法容纳在work_mem,则可以通过有损(“go lossy”)存储blockes的bitmap。它可以有选择地执行此操作,因此一些块可以有损转换,而其他块则不会。

如果它变得有损,那么Heap Scan必须recheck它访问的每个有损块中的每一行,由于一个heap 页面可以包含多个元组,因为它不再具有有关该块中哪些特定行符合搜索条件的信息。

 

Bitmap Index Scan

可以将位图索引扫描视为顺序扫描和索引扫描之间的中间地带。与索引扫描一样,它扫描索引以确定需要获取的确切数据,但与顺序扫描一样,它利用数据更易于批量读取的优势。

位图索引扫描实际上与位图堆扫描协同运行:它不获取数据本身。位图索引扫描不是直接生成行,而是构造潜在行位置的位图。它将此数据提供给父位图堆扫描,该扫描可以解码位图以获取基础数据,逐页抓取数据。位图扫描是一个多步骤过程,由位图堆扫描、一个或多个位图索引扫描以及可选的 BitmapOr 和 BitmapAnd 操作组成。位图索引扫描是第一步,使用索引创建可能满足(至少部分)条件的行的位图。

Heap Blocks: exact
如果row bitmap太大而无法放入工作内存 (work_mem),则它的某些部分会变得“有损”lossy——即它们引用整个页面而不是特定的 rows.work_mem. 位图堆扫描访问的非有损block的数量。如果行位图太大而无法放入工作内存 (work_mem),则它的某些部分将成为“有损”——即它们指的是整个页面而不是特定的rows。

“堆块:exact=1”表示它只访问了1个块,并且它没有损失。

Recheck Cond

Recheck Cond 是位图扫描在获取行后可能用来过滤行的条件。只有当位图扫描是有损的,或者它使用了任何不保证行匹配条件的有损索引类型时才需要它(BRIN 索引就是一个例子)。

有关是否确实需要重新检查的更多信息, look out for non-zero Lossy Heap Blocks and non-zero Rows Removed by Index Recheck.

解读上图执行计划过程

SQL 索引查找需要

(1) Bitmap Index Scan遍历 (查询将遍历 B 树以快速找到包含行的页面。行本身是双向链表中的节点),构建bitmaps

(2) Heap Blocks 根据扫描确认heap block 实际就1 block

(3) Bitmap Heap Scan获取表数据。需要Recheck 条件otype = ‘i’的行记录.

— over, 如果不对之处请指正

打赏

, ,

对不起,这篇文章暂时关闭评论。