Postgres 可为空列上的部分索引与常规/完整索引

nma*_*akb 3 postgresql indexing null partial-index

我有一个包含 1m 条记录的表,其中 100k 条记录为 null colA。其余记录具有非常不同的值,在此列上创建常规索引与使用 的部分索引有区别吗where colA is not null

由于常规 Postgres 索引不存储 NULL 值,那么它不是与使用 创建部分索引相同吗where colA is not null
这两个指数有什么优点或缺点吗?

Sch*_*ern 5

如果您创建不带空值的部分索引,则它不会使用它来查找空值。

这是在 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)
Run Code Online (Sandbox Code Playgroud)

并带有部分索引。

# 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)
Run Code Online (Sandbox Code Playgroud)

由于常规 postgres 索引不存储 NULL 值...

自 16 年前的 8.2 版 [检查注释] 以来,情况并非如此。8.2 文档说...

默认情况下,IS NULL 子句不使用索引。在这种情况下使用索引的最佳方法是使用 IS NULL 谓词创建部分索引。

8.3 引入了 nulls first围绕nulls last空值的许多其他改进,包括......

允许 col IS NULL 使用索引 (Teodor)