我的问题是,当具有相等信息(我认为)的部分索引被使用时,为什么多列索引不用于仅索引扫描。
表格:
CREATE TABLE test
(
id INT,
descr TEXT,
flag BOOLEAN
);
INSERT INTO test
SELECT GENERATE_SERIES(1,100000) AS id,
MD5(RANDOM()::TEXT) AS descr,
(RANDOM() < 0.1) AS flag;
SELECT *
FROM test LIMIT 10;
内容样本:
id descr flag
1 81978ceb5514461fbad9af1152ad78f6 true
2 cc0aee68ba3e0095cc74d53e8da55fef false
3 689a76e5897d565638f8ddd2d2019b7a true
4 9df03bc2969a6af88cd1d6e0423d0f4c true
5 318983766d11f831e9f0df34606dc908 false
6 198102bb71640a16f28263b7fb56ba2e false
7 9bef7320389db46a8ad88ffa611e81b5 false
8 c1f0d637ee0a985aa7d768a78d2d97b1 false
9 781b4064f721ae3879d95579264b0aba false
10 c4582890bb1e9af430e0f36b50f5e88c false
我需要运行的查询是:
SELECT id
FROM test
WHERE flag;
现在,如果我使用部分索引。该查询(最终)被执行为仅索引扫描:
CREATE INDEX i1
ON test (id) WHERE flag;
QUERY PLAN
Index Only Scan using i1 on test (cost=0.29..354.95 rows=9911 width=4) (actual time=0.120..6.268 rows=9911 loops=1)
Heap Fetches: 9911
Buffers: shared hit=834 read=29
Planning time: 0.806 ms
Execution time: 6.922 ms
我不明白的是:为什么以下形式的多列索引从未用于仅索引扫描?
CREATE INDEX i2
ON test (flag, id);
QUERY PLAN
Bitmap Heap Scan on test (cost=189.10..1122.21 rows=9911 width=4) (actual time=0.767..5.986 rows=9911 loops=1)
Filter: flag
Heap Blocks: exact=834
Buffers: shared hit=863
-> Bitmap Index Scan on i2 (cost=0.00..186.62 rows=9911 width=0) (actual time=0.669..0.669 rows=9911 loops=1)
Index Cond: (flag = true)
Buffers: shared hit=29
Planning time: 0.090 ms
Execution time: 6.677 ms
查询不能访问标志为True
的btree的所有连续叶子以确定所有ID?
(请注意,由于仅索引扫描与部分索引i1
一起使用,所以元组可见性可能不是问题。)
我的Postgres版本是:PostgreSQL 9.6.2 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.3.1-14ubuntu2) 5.3.1 20160413, 64-bit
答案 0 :(得分:1)
无法确定系统上行为的确切原因,可能是由于统计数据错误或可见性图不正确而误导了PostgreSQL优化器。
VACUUM (ANALYZE) test;
会做两件事:
它将更新可见性图,这对于PostgreSQL是否能够执行仅索引扫描做出明智的决定是必要的。
它将收集表中的统计信息,这将使PostgreSQL准确估算结果行的数量,从而可以选择最佳计划。