我有一个包含 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<>在这里摆弄
因此,这取决于完整的图片。