为什么使用 GiST 索引来过滤非前导列?

Kej*_*jlo 6 postgresql index-tuning gist-index postgresql-12

我总是了解到并理解,只有当我们对前导(或所有)列有谓词时才能使用索引。现在,令我惊讶的是,我注意到以下查询中使用了GiST 索引。这是为什么?这是 GiST 索引的特殊功能吗?

CREATE TABLE t1 (
    i INT, 
    j INT, 
    k INT
);

INSERT INTO t1 
SELECT i, j, k 
FROM   GENERATE_SERIES(1, 100) AS i, 
       GENERATE_SERIES(1, 100) AS j, 
       GENERATE_SERIES(1, 100) AS k;

CREATE INDEX ON t1 USING GiST(i, j, k);

EXPLAIN SELECT * FROM t1 WHERE k = 54;
Run Code Online (Sandbox Code Playgroud)
QUERY PLAN
Bitmap Heap Scan on t1  (cost=199.03..5780.51 rows=5000 width=12)
  Recheck Cond: (k = 54)
  ->  Bitmap Index Scan on t1_i_j_k_idx  (cost=0.00..197.78 rows=5000 width=0)
        Index Cond: (k = 54)
Run Code Online (Sandbox Code Playgroud)

db<>在这里摆弄

Erw*_*ter 6

仅当我们对前导(或所有)列有谓词时才能使用索引。

在 Postgres 中,这条经验法则仅在某种程度上适用于(默认)B 树索引。看:

但对于GiST索引来说大多是错误的。手册:

多列 GiST 索引可与涉及索引列的任何子集的查询条件一起使用。其他列上的条件限制索引返回的条目,但第一列上的条件对于确定需要扫描多少索引是最重要的。如果 GiST 索引的第一列只有几个不同的值,即使其他列中有许多不同的值,GiST 索引也会相对无效。

因此,通常,您会将具有最不同值的列(或表达式)放在 GiST 索引中的前面。

有关的:

对于其他索引类型而言,情况有所不同。对于(也很常见)GIN索引:

多列 GIN 索引可与涉及索引列的任何子集的查询条件一起使用。与 B 树或 GiST 不同,无论查询条件使用哪个索引列,索引搜索效率都是相同的。

建议阅读本手册的整章。