是否可以在 PostgreSQL 中索引数组列的位置?

Posted

技术标签:

【中文标题】是否可以在 PostgreSQL 中索引数组列的位置?【英文标题】:Is it possible to index the position of an array column in PostgreSQL? 【发布时间】:2021-12-17 22:59:47 【问题描述】:

假设我想在表my_table 中查找在数组列my_array_column 的第一个位置具有值5 的行。为了准备表格,我执行了以下语句:

CREATE TABLE my_table (
    id serial primary key,
    my_array_column  integer[]
);

CREATE INDEX my_table_my_array_column_index on "my_table" USING GIN ("my_array_column");

SET enable_seqscan TO off;

INSERT INTO my_table (my_array_column) VALUES ('5,7,10');

现在,查询可能如下所示:

select * from my_table where my_array_column[1] = 5;

这可行,但它不使用创建的 GIN 索引。是否可以通过索引在特定位置搜索值5

【问题讨论】:

【参考方案1】:

我想在表 my_table 中查找在数组列的第一个位置具有值 5 的行

partial index 对于该定义最有效:

CREATE INDEX my_table_my_array_special_idx ON my_table ((true))
WHERE my_array_column[1] = 5;

如果只有一小部分行符合条件,则部分索引会相应地更小。另外,实际的索引列只占用最小的空间(通常是 8 个字节)。而且,最重要的是,Postgres 13 或更高版本可以应用 index deduplication 来使索引更小。

一旦索引被完全缓存,它的小尺寸并没有使它更快,但仍然。 而且大多数写入不必操作索引,这可能是最重要的好处,具体取决于工作负载。

哦,Postgres 会收集部分索引的统计信息。因此,当涉及到该索引时,您可以期望查询规划器做出充分的选择。

相关:

PostgreSQL partial index unused when created on a table with existing data Index that is not used, yet influences query

当查询重复相同条件时适用。

通常,您有一些有用的索引字段在您声明的目的的顶部。但如果你不这样做,只需使用任何小的常量 - 在我的示例中为 true,但任何

次要免责声明:Postgres 数组中的“第一个位置”不一定有索引 1。如果可以使用非标准数组索引,请考虑:

...
WHERE (my_array_column[:])[1] = 5;

在索引查询中。

见:

Normalize array subscripts for 1-dimensional array so they start with 1

【讨论】:

【参考方案2】:

您可以只索引第一个位置。您需要在 create 语句中使用一组额外的括号来执行此操作:

create index on my_table ((my_array_column[1]));

或者你可以扩充你的查询来使用你的 gin 索引,理论上一个数组不能有第一个元素是 5,除非至少一个元素是 5。

select * from my_table where my_array_column[1] = 5 and my_array_column @> ARRAY[5];

当然,如果您的许多数组包含 5,但在数组中的其他位置,这将不是很有效。它必须重新检查所有这些“错误匹配”以消除它们。所以如果你只关心第一个元素,我展示的第一个索引会更好。 (当然,如果只关心第一个元素,为什么要用数组开头呢?)

【讨论】:

【参考方案3】:

如果您总是查看第一个位置,则常规 B-Tree 索引会这样做:

create index on my_table ( (my_array_column[1]) );

如果您不知道位置,则确实需要 GIN 索引,但您需要使用 is supported 通过 gin 索引的运算符,例如@> 运算符。但为此,您需要使用不同的查询:

select *
from my_table
where my_array_column @> array[5];

这将找到数组列包含值 5 的所有行。


但是你应该参考手册中关于数组使用的建议:

数组不是集合;搜索特定的数组元素可能是数据库设计错误的标志。考虑使用一个单独的表,其中每个项目将是一个数组元素。这将更容易搜索,并且对于大量元素可能会更好地扩展。

【讨论】:

这似乎是一个语法错误:[42601] ERROR: syntax error at or near ")" @plenox 抱歉,您需要用括号将表达式括起来

以上是关于是否可以在 PostgreSQL 中索引数组列的位置?的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 可以索引数组列吗?

PostgreSQL 多列索引,包括数组

Postgresql 可以在数组长度上创建索引吗?

PostgreSQL 上所有列的索引

PostgreSQL中如何查询索引的元数据

如何从 PostgreSQL 的子查询中选择包含值数组的列?