我有一个包含 1m 条记录的表,其中 100k 条记录具有 null on colA。其余记录具有非常不同的值,在此列上创建常规索引与使用 的部分索引是否有区别where colA is not null?
由于常规 Postgres 索引不存储 NULL 值,它与创建部分索引不一样where colA is not null吗?
任何一个索引都有什么优点或缺点?
我有一个包含 1m 条记录的表,其中 100k 条记录具有 null on colA。其余记录具有非常不同的值,在此列上创建常规索引与使用 的部分索引是否有区别where colA is not null?
由于常规 Postgres 索引不存储 NULL 值,它与创建部分索引不一样where colA is not null吗?
任何一个索引都有什么优点或缺点?
如果您创建没有空值的部分索引,它将不会使用它来查找空值。
这是一个关于 13.5 的完整索引的测试。
# create index idx_test_num on test(num);
CREATE INDEX
# explain select count(*) from test where num is null;
QUERY PLAN
-------------------------------------------------------------------------------------
Aggregate (cost=5135.00..5135.01 rows=1 width=8)
-> Bitmap Heap Scan on test (cost=63.05..5121.25 rows=5500 width=0)
Recheck Cond: (num IS NULL)
-> Bitmap Index Scan on idx_test_num (cost=0.00..61.68 rows=5500 width=0)
Index Cond: (num IS NULL)
(5 rows)
并带有部分索引。
# create index idx_test_num on test(num) where num is not null;
CREATE INDEX
# explain select count(*) from test where num is null;
QUERY PLAN
--------------------------------------------------------------------------------------
Finalize Aggregate (cost=10458.12..10458.13 rows=1 width=8)
-> Gather (cost=10457.90..10458.11 rows=2 width=8)
Workers Planned: 2
-> Partial Aggregate (cost=9457.90..9457.91 rows=1 width=8)
-> Parallel Seq Scan on test (cost=0.00..9352.33 rows=42228 width=0)
Filter: (num IS NULL)
(6 rows)
由于常规 postgres 索引不存储 NULL 值...
自 16 年前的 8.2 版 [检查笔记] 以来,情况并非如此。8.2文档说...
默认情况下,索引不用于 IS NULL 子句。在这种情况下使用索引的最佳方法是使用 IS NULL 谓词创建部分索引。
8.3 引入 nulls first和nulls last许多其他围绕空值的改进,包括...
允许 col IS NULL 使用索引 (Teodor)
这一切都取决于。
NULL自 Postgres 8.3 版本起,值包含在(默认)B-tree 索引中,就像 Schwern 提供的一样。但是,自Postgres 9.0起,您提到的谓词 ( where colA is not null) 才得到适当的支持。发行说明:
允许
IS NOT NULL限制使用索引 (Tom Lane)这对于在包含许多空值的索引中查找
MAX()/值特别有用。MIN()
GIN 索引紧随其后:
从 PostgreSQL 9.1 开始,空键值可以包含在索引中。
通常,如果部分索引从索引中排除了表的主要部分,则它是有意义的,使其显着变小并节省对索引的写入。由于 B-tree 索引非常浅,因此裸寻道性能可以惊人地扩展(一旦索引被缓存)。减少 10 % 的索引条目在该领域几乎无关紧要。
您的案例将仅排除所有行的 10% 左右,而且很少有回报。部分索引为查询计划器增加了一些开销,并排除了与索引条件不匹配的查询。(如果匹配不是很明显,Postgres 查询规划器不会努力。)
OTOH,Postgres 很少使用索引来检索表的 10% 的谓词 - 顺序扫描通常会更快。再次,这取决于。
如果(几乎)所有查询都排除NULL(以 Postgres 规划器理解的方式),那么仅排除所有行的 10% 的部分索引仍然是一个明智的选择。但如果查询模式发生变化,它可能会适得其反。增加的复杂性可能不值得。
另外值得注意的是,NULL在 Postgres 索引中仍然存在带有值的极端情况。我最近遇到了这种情况,当第一个索引表达式被过滤时,Postgres 证明不愿意从多列索引中读取已排序的行IS NULL(使部分索引更适合这种情况):
db<>在这里摆弄
因此,这取决于完整的图片。