我创建了下面的例子,但不明白为什么计划员不使用索引i2
进行查询。它知道列uniqueIds
包含唯一的值,也知道列fourOtherIds
只包含4个不同的值,那么搜索索引i2
不是最快的方法吗?只在fourOtherIds
的四个不同索引叶中查找uniqueIds
?我对索引工作原理的理解有什么问题?为什么它认为使用i1
在这里更有意义,即使它必须过滤掉333.333行?在我的理解中,它应该使用i2
来查找一行(或很少的行,因为没有唯一约束),其首先具有uniqueIds
4000,然后应用where fourIds = 1
作为过滤器。
create table t (fourIds int, uniqueIds int,fourOtherIds int);
insert into t ( select 1,*,5 from generate_series(1 ,1000000));
insert into t ( select 2,*,6 from generate_series(1000001,2000000));
insert into t ( select 3,*,7 from generate_series(2000001,3000000));
insert into t ( select 4,*,8 from generate_series(3000001,4000000));
create index i1 on t (fourIds);
create index i2 on t (fourOtherIds,uniqueIds);
analyze t;
select n_distinct,attname from pg_stats where tablename = 't';
/*
n_distinct|attname |
----------+------------+
4.0|fourids |
-1.0|uniqueids |
4.0|fourotherids|
*/
explain analyze select * from t where fourIds = 1 and uniqueIds = 4000;
/*
QUERY PLAN |
--------------------------------------------------------------------------------------------------------------------------+
Gather (cost=1000.43..22599.09 rows=1 width=12) (actual time=0.667..46.818 rows=1 loops=1) |
Workers Planned: 2 |
Workers Launched: 2 |
-> Parallel Index Scan using i1 on t (cost=0.43..21598.99 rows=1 width=12) (actual time=25.227..39.852 rows=0 loops=3)|
Index Cond: (fourids = 1) |
Filter: (uniqueids = 4000) |
Rows Removed by Filter: 333333 |
Planning Time: 0.107 ms |
Execution Time: 46.859 ms |
*/
1条答案
按热度按时间5t7ly7z51#
并不是所有的优化都已经实现了,你正在寻找一个index skip scan的变体,也就是一个松散的索引扫描,PostgreSQL不会自动实现这些(然而--人们正在研究它,但我不知道他们是否还在研究。另外,我想我读到过第三方扩展/分支之一,可能是citus,已经实现了它)。您可以使用递归CTE自己模拟一个扩展a分支,但那样做会很烦人。