在 PostgreSQL12.1
上,给出:
postgres=> create table abc(a int not null, b text not null, c boolean not null);
CREATE TABLE
postgres=> create index on abc (a, b, c);
CREATE INDEX
然后我准备了一个只过滤 的查询a
,即索引中的第一个元素。
postgres=> prepare only_a(int) as select 42 from abc where a = 1;
PREPARE
postgres=> explain execute only_a(100);
QUERY PLAN
----------------------------------------------------------------------------
Bitmap Heap Scan on abc (cost=4.20..13.67 rows=6 width=4)
Recheck Cond: (a = 1)
-> Bitmap Index Scan on abc_a_b_c_idx (cost=0.00..4.20 rows=6 width=0)
Index Cond: (a = 1)
(4 rows)
根据上述内容,它可以使用索引来过滤a
。
然后,我准备了一个过滤a
和的查询c
,即不使用b
。
postgres=> prepare a_and_c(int) as select 42 from abc where a = 1 and c = true;
PREPARE
然后,我跑了explain execute
,
postgres=> explain execute a_and_c(100);
QUERY PLAN
----------------------------------------------------------------------------
Bitmap Heap Scan on abc (cost=4.21..11.32 rows=3 width=4)
Recheck Cond: (a = 1)
Filter: c
-> Bitmap Index Scan on abc_a_b_c_idx (cost=0.00..4.21 rows=3 width=0)
Index Cond: ((a = 1) AND (c = true))
(5 rows)
我的理解是,这意味着Index Cond: ((a = 1) AND (c = true))
尽管没有参与.abc_a_b_c_idx
a
c
b
where
如果可以,c
既然b
不使用怎么能使用?
“c”只是用作索引过滤器。它跳转到索引中“a”=1 的部分并对其进行扫描,直到“a”变为 >1。对于所有这些行,它会根据索引中找到的“c”值过滤掉“c”不正确的任何内容。
不幸的是,EXPLAIN 语法没有区分用于跳转到索引的特定部分(或在相关值末尾停止索引扫描)的列与仅用于在索引中过滤的列。但是 EXPLAIN 不了解索引的内部结构,它只知道“c”正在被使用,它不知道它的使用效率如何。
您想知道是对的,原因是 PostgreSQL 的解释输出中的马虎。
在索引扫描期间,有些条件可以用来扫描索引,有些条件可以用作过滤器,这是对在索引扫描期间找到的行施加的附加条件。
现在
a = 1
显然是可以用于扫描索引的条件。问题是在索引扫描期间有两种过滤方式:
在访问表之前,在扫描索引元组时丢弃它们。
根据在索引扫描期间从表中获取的值的条件丢弃结果行。
第二种显示为
filter
,EXPLAIN
但第一种过滤器显示为扫描条件的一部分。这就是你的条件c = true
。EXPLAIN
无法从输出中的第一类过滤器中分辨出扫描条件。请注意,第一种过滤器更有效,因为它减少了必须从堆中提取的行数,这是索引扫描的昂贵部分。