PostgreSQL 可以索引数组列吗?

问题描述 投票:0回答:3

我在文档中找不到这个问题的明确答案。如果列是数组类型,所有输入的值都会单独索引吗?

我创建了一个简单的表,其中有一个

int[]
列,并在其上放置了唯一索引。我注意到我无法添加相同的整数数组,这使我相信索引是数组项的组合,而不是每个项的索引。

INSERT INTO "Test"."Test" VALUES ('{10, 15, 20}');
INSERT INTO "Test"."Test" VALUES ('{10, 20, 30}');

SELECT * FROM "Test"."Test" WHERE 20 = ANY ("Column1");

索引对这个查询有帮助吗?

arrays postgresql indexing operators
3个回答
263
投票

是的,您可以索引数组,但您必须使用 数组运算符GIN 索引类型

示例:

    CREATE TABLE "Test"("Column1" int[]);
    INSERT INTO "Test" VALUES ('{10, 15, 20}');
    INSERT INTO "Test" VALUES ('{10, 20, 30}');
    
    CREATE INDEX idx_test on "Test" USING GIN ("Column1" gin__int_ops);
            
    EXPLAIN ANALYZE
    SELECT * FROM "Test" WHERE "Column1" @> ARRAY[20];

结果:

Bitmap Heap Scan on "Test"  (cost=4.26..8.27 rows=1 width=32) (actual time=0.014..0.015 rows=2 loops=1)
  Recheck Cond: ("Column1" @> '{20}'::integer[])
  ->  Bitmap Index Scan on idx_test  (cost=0.00..4.26 rows=1 width=0) (actual time=0.009..0.009 rows=2 loops=1)
        Index Cond: ("Column1" @> '{20}'::integer[])
Total runtime: 0.062 ms

注意

看来在很多情况下需要 gin__int_ops 选项

create index <index_name> on <table_name> using GIN (<column> gin__int_ops)

我还没有见过在没有 gin__int_ops 选项的情况下可以与 && 和 @> 运算符一起使用的情况


143
投票

@Tregoreg 在对他提供的赏金的评论中提出了问题

我发现当前的答案不起作用。使用 GIN 索引 数组类型的列不会提高 ANY() 的性能 操作员。真的没有办法解决吗?

@Frank 接受的 答案 告诉您使用 数组运算符,这对于 Postgres 11 来说仍然正确手册:

...PostgreSQL 的标准发行版包含一个 GIN 运算符 数组类,支持使用这些索引查询 运营商:

<@
@>
=
&&

标准发行版中 GIN 索引的内置运算符类的完整列表位于此处。

在 Postgres 中索引绑定到运算符(针对某些类型实现),而不是单独的数据类型或函数或其他任何东西。这是 Postgres 的 伯克利原始设计的遗产,现在很难改变。而且它通常工作得很好。 这里有一个关于 pgsql-bugs 的帖子,Tom Lane 对此发表了评论。

一些 PostGis functions(如

ST_DWithin()
)似乎违反了这一原则,但事实并非如此。这些函数在内部重写以使用各自的运算符

索引表达式必须位于运算符的left。对于大多数运算符(包括上述所有运算符),如果将索引表达式放在右侧,则查询规划器可以通过翻转操作数来实现此目的 - 假设已经定义了

COMMUTATOR
ANY
构造
可以与各种运算符结合使用,但它本身并不是一个运算符。当用作
constant = ANY (array_expression)
时,只有支持
=
数组元素 运算符的索引才符合资格,并且我们需要
= ANY()
的换向器。 GIN 索引已出炉。

Postgres 目前还不够智能,无法从中导出 GIN 可索引表达式。对于初学者来说,

constant = ANY (array_expression)
不完全等同于array_expression @> ARRAY[constant]
。如果涉及任何 NULL 
elements,数组运算符将返回错误,而 ANY
 构造可以处理任一侧的 NULL。并且数据类型不匹配会有不同的结果。

相关解答:

  • 检查Postgres数组中是否存在值

  • 用于在 JSON 数组中查找元素的索引

  • SQLAlchemy:如何过滤 PgArray 列类型?

  • IS DISTINCT FROM 可以以某种方式与 ANY 或 ALL 组合吗?

旁白

在使用

integer

 数组
int4
,不是 
int2
int8
)而没有 
NULL
 值(如您的示例所示)时,请考虑附加模块 
intarray
,它提供了专门的,更快的运算符和索引支持。参见:

  • 如何在 PostgreSQL 中为数组的元素创建索引?
  • 比较数组是否相等,忽略元素的顺序
至于您问题中未得到解答的

UNIQUE

 约束:这是通过 
整个数组 值上的 btree 索引实现的(就像您怀疑的那样),并且根本无法帮助搜索 elements 。详情:

  • PostgreSQL 如何强制执行 UNIQUE 约束/它使用什么类型的索引?

37
投票
现在可以对各个数组元素进行索引。例如:

CREATE TABLE test (foo int[]); INSERT INTO test VALUES ('{1,2,3}'); INSERT INTO test VALUES ('{4,5,6}'); CREATE INDEX test_index on test ((foo[1])); SET enable_seqscan TO off; EXPLAIN ANALYZE SELECT * from test WHERE foo[1]=1; QUERY PLAN ------------------------------------------------------------------------------------------------------------------ Index Scan using test_index on test (cost=0.00..8.27 rows=1 width=32) (actual time=0.070..0.071 rows=1 loops=1) Index Cond: (foo[1] = 1) Total runtime: 0.112 ms (3 rows)

这至少适用于 Postgres 9.2.1。请注意,您需要为每个数组索引构建一个单独的索引,在我的示例中,我只索引了第一个元素。

© www.soinside.com 2019 - 2024. All rights reserved.