PostgreSQL可以索引数组列吗?

xtupzzrd  于 2023-06-05  发布在  PostgreSQL
关注(0)|答案(3)|浏览(695)

我在文档中找不到这个问题的明确答案。如果列是数组类型,所有输入的值都将单独索引吗?
我创建了一个包含一个int[]列的简单表,并在其上放置了一个唯一索引。我注意到我不能添加相同的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");

索引是否有助于此查询?

l5tcr1uw

l5tcr1uw1#

是的,你可以索引一个数组,但是你必须使用array operatorsGIN-index type
示例:

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");

    -- To enforce index usage because we have only 2 records for this test... 
    SET enable_seqscan TO off;

    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选项

xdyibdwo

xdyibdwo2#

@Tregoreg在评论中对他提供的赏金提出了一个***问题***:
我不认为当前的答案有效。对数组类型的列使用GIN索引不会提高ANY()运算符的性能。真的没有解决办法吗?
@Frank接受的*答案*告诉你使用数组运算符,这对Postgres 11来说 * 仍然是正确的 *。The manual:
... PostgreSQL的标准发行版包括一个用于数组的GIN运算符类,它支持使用以下运算符进行索引查询:

<@
@>
=
&&

标准发行版中GIN索引的内置运算符类的完整列表在这里。
在Postgres中,索引被绑定到运算符(这是为某些类型实现的),而不是单独的数据类型或函数或其他任何东西。这是一个heritage from the original Berkeley design of Postgres,现在很难改变。一般来说,它工作得很好。这里有一个关于pgsql bug的帖子,Tom Lane对此进行了评论。
一些PostGis * 函数 *(如ST_DWithin())似乎违反了这一原则,但事实并非如此。这些函数在内部被重写以使用各自的 * 运算符 *。
索引表达式必须位于运算符的 * 左侧 。对于大多数操作符( 包括以上所有 *),如果将索引表达式放在右侧,查询规划器可以通过翻转操作数来实现这一点-假设已经定义了COMMUTATORANY结构可以与各种运算符组合使用,本身不是运算符。当用作constant = ANY (array_expression)时,只有在 array elements 上支持=运算符的索引才符合条件,我们需要= ANY()的转换器。GIN指数出来了。
Postgres目前还不够智能,无法从中派生出一个GIN可索引的表达式。对于初学者来说,constant = ANY (array_expression)**不完全等同于array_expression @> ARRAY[constant]。如果涉及任何NULL * 元素 *,数组运算符将返回错误,而ANY结构可以处理任何一侧的NULL。对于数据类型不匹配,会有不同的结果。
相关回答:

旁白

在使用没有NULL值的**integer数组**(int4,而不是int2int8)时(如您的示例所示),请考虑额外的模块intarray,它提供了专门的,更快的运算符和索引支持。参见:

  • 如何在PostgreSQL中为数组的元素创建索引?
  • 比较数组是否相等,忽略元素的顺序

至于你的问题中没有回答的UNIQUE约束:这是在 whole array 值上使用btree索引实现的(就像你怀疑的那样),对搜索 elements 根本没有帮助。详细内容:

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

ykejflvf3#

现在可以对单个数组元素进行索引。例如:

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上有效。请注意,您需要为每个数组索引构建一个单独的索引,在我的示例中,我只索引了第一个元素。

相关问题