我不了解位图堆扫描节点的基本原理.考虑查询SELECT customerid,用户名FROM customers WHERE customerid< 1000 AND username<'user100';计划是这样的:
Bitmap Heap Scan on customers (cost=25.76..61.62 rows=10 width=13) (actual time=0.077..0.077 rows=2 loops=1) Recheck Cond: (((username)::text < 'user100'::text) AND (customerid < 1000)) -> BitmapAnd (cost=25.76..25.76 rows=10 width=0) (actual time=0.073..0.073 rows=0 loops=1) -> Bitmap Index Scan on ix_cust_username (cost=0.00..5.75 rows=200 width=0) (actual time=0.006..0.006 rows=2 loops=1) Index Cond: ((username)::text < 'user100'::text) -> Bitmap Index Scan on customers_pkey (cost=0.00..19.75 rows=1000 width=0) (actual time=0.065..0.065 rows=999 loops=1) Index Cond: (customerid < 1000)
我对这个节点的理解:
正如there所解释的,位图堆扫描按顺序读取表块,因此它不会产生随机表访问开销,这种情况就像只执行索引扫描一样.
完成索引扫描后,Postgresql不知道如何以最佳方式获取行,以避免不必要的堆块读取(或者如果存在热缓存则命中).因此,要弄清楚它会生成一个名为位图的结构(位图索引扫描),在我的情况下,它是通过生成索引的两个位图并执行BITWISE AND来生成的.由于已生成位图,因此它现在可以按顺序最佳地读取表,从而避免不必要的堆I / O操作.
那是很多问题的来源.
问题:我们只有一个位图. Postgresql如何通过位图了解行的物理顺序?或者生成位图,以便它的任何元素可以轻松地映射到指向页面的指针?如果是这样,那就解释了一切,但这只是我的猜测.
那么,我们可以简单地说位图堆扫描 – >位图索引扫描就像是顺序扫描,但只是表的适当部分?
How does Postgresql knows by just a bitmap anything about rows’ physical order?
位图是每堆页面一位.位图索引扫描根据索引条目指向的堆页面地址设置位.
因此,当它进行位图堆扫描时,它只进行线性表扫描,读取位图以查看它是否应该打扰特定页面或寻找它.
Or generates the bitmap so that any element of it can be mapped to the pointer to a page easily?
不,位图与堆页面对应1:1.
我在here上写了更多.
好吧,看起来你可能误解了“位图”在这种情况下的含义.
它不是像“101011”那样为每个堆页面或每个索引读取创建的字符串,或者其他任何东西.
整个位图是单个bit array,其数量与扫描关系中的堆页数一样多.
第一个索引扫描创建一个位图,从所有条目0(false)开始.每当找到与搜索条件匹配的索引条目时,该索引条目指向的堆地址将被查找为位图的偏移量,并且该位设置为1(true).因此,位图索引扫描不是直接查找堆页面,而是查找位图中相应的位位置.
第二个和更多位图索引扫描与其他索引及其上的搜索条件执行相同的操作.
然后将每个位图进行AND运算.得到的位图对于每个堆页面具有一个位,其中只有在所有单独的位图索引扫描中它们都为真时才是真,即对于每个索引扫描匹配的搜索条件.这些是我们需要费心加载和检查的唯一堆页面.由于每个堆页面可能包含多行,因此我们必须检查每一行以查看它是否与所有条件匹配 – 这就是“recheck cond”部分的内容.
理解所有这一切的一个重要的事情是索引条目中的元组地址指向行的ctid,它是堆页面编号和堆页面内的偏移量的组合.位图索引扫描会忽略偏移量,因为它无论如何都会检查整个页面,如果该页面上的任何行与条件匹配,则设置该位.
图形示例
Heap,one square = one page: +---------------------------------------------+ |c____u_____X___u___X_________u___cXcc______u_| +---------------------------------------------+ Rows marked c match customers pkey condition. Rows marked u match username condition. Rows marked X match both conditions. Bitmap scan from customers_pkey: +---------------------------------------------+ |100000000001000000010000000000000111100000000| bitmap 1 +---------------------------------------------+ One bit per heap page,in the same order as the heap Bits 1 when condition matches,0 if not Bitmap scan from ix_cust_username: +---------------------------------------------+ |000001000001000100010000000001000010000000010| bitmap 2 +---------------------------------------------+
一旦创建了位图,就会对它们执行按位AND:
+---------------------------------------------+ |100000000001000000010000000000000111100000000| bitmap 1 |000001000001000100010000000001000010000000010| bitmap 2 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& |000000000001000000010000000000000010000000000| Combined bitmap +-----------+-------+--------------+----------+ | | | v v v Used to scan the heap only for matching pages: +---------------------------------------------+ |___________X_______X______________X__________| +---------------------------------------------+
+---------------------------------------------+ |___________X_______X______________X__________| +---------------------------------------------+ seek------->^seek-->^seek--------->^ | | | ------------------------ only these pages read
然后根据条件重新检查每个读取页面每页可以有> 1行而不是所有都必须匹配条件.