我在文档中找不到这个问题的明确答案。如果列是数组类型,所有输入的值都会单独索引吗?
我创建了一个简单的表,其中有一个
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");
索引对这个查询有帮助吗?
是的,您可以索引数组,但您必须使用 数组运算符 和 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 选项的情况下可以与 && 和 @> 运算符一起使用的情况
@Tregoreg 在对他提供的赏金的评论中提出了问题:
我发现当前的答案不起作用。使用 GIN 索引 数组类型的列不会提高 ANY() 的性能 操作员。真的没有办法解决吗?
@Frank 接受的 答案 告诉您使用 数组运算符,这对于 Postgres 11 来说仍然正确。手册:
...PostgreSQL 的标准发行版包含一个 GIN 运算符 数组类,支持使用这些索引查询 运营商:
<@ @> = &&
标准发行版中 GIN 索引的内置运算符类的完整列表位于此处。
在 Postgres 中索引绑定到运算符(针对某些类型实现),而不是单独的数据类型或函数或其他任何东西。这是 Postgres 的 伯克利原始设计的遗产,现在很难改变。而且它通常工作得很好。 这里有一个关于 pgsql-bugs 的帖子,Tom Lane 对此发表了评论。
ST_DWithin()
)似乎违反了这一原则,但事实并非如此。这些函数在内部重写以使用各自的运算符。
索引表达式必须位于运算符的left。对于大多数运算符(包括上述所有运算符),如果将索引表达式放在右侧,则查询规划器可以通过翻转操作数来实现此目的 - 假设已经定义了
COMMUTATOR
。 ANY
构造 可以与各种运算符结合使用,但它本身并不是一个运算符。当用作 constant = ANY (array_expression)
时,只有支持=
数组元素 运算符的索引才符合资格,并且我们需要 = ANY()
的换向器。 GIN 索引已出炉。
Postgres 目前还不够智能,无法从中导出 GIN 可索引表达式。对于初学者来说,
constant = ANY (array_expression)
不完全等同于array_expression @> ARRAY[constant]
。如果涉及任何 NULLelements,数组运算符将返回错误,而
ANY
构造可以处理任一侧的 NULL。并且数据类型不匹配会有不同的结果。相关解答:
integer
数组(
int4
,不是
int2
或
int8
)而没有
NULL
值(如您的示例所示)时,请考虑附加模块
intarray
,它提供了专门的,更快的运算符和索引支持。参见:
至于您问题中未得到解答的 UNIQUE
约束:这是通过整个数组 值上的 btree 索引实现的(就像您怀疑的那样),并且根本无法帮助搜索 elements 。详情:
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。请注意,您需要为每个数组索引构建一个单独的索引,在我的示例中,我只索引了第一个元素。