如何在PostgreSQL中为数组元素创建索引?

时间:2012-06-03 03:03:02

标签: sql arrays postgresql indexing

使用此架构:

create table object (
   obj_id      serial      primary key,
   name        varchar(80) not null unique,
   description text,
   tag_arr     int[]
);

create table tag (
   tag_id      serial      primary key,
   label       varchar(20) not null unique
);

对象可以附加任意数量的标签。我希望将object X tag保存在数组中,而不是tag_id表,以便可以使用对象记录轻松获取它们。

如何在object上创建索引,以便tar_arr的每个元素都是索引?

那说,有没有更好的方法来解决这个问题?

讨论

这可以通过以下方式实现:

create table obj_x_tag(
   obj_id    references object,
   tag_id    references tag,
   constraint obj_x_tag_pk primary key( obj_id, tag_id )
);

select obj_id, name, description, array_agg( tag_id )
from object o
join obj_x_tag x using( obj_id )
group by 1, 2;

但对我而言,将tag_id的数组保留在一列中并省去交叉表并array_agg()

更有意义

建议使用PostgresQL SQL: Converting results to array。如前所述,问题在于“这实际上并不索引单个数组值,而是索引整个数组”

还建议使用pg的intarrgist(或gin)索引。问题 - 对我来说 - 似乎索引是针对标准的基于pg集的数组运算符,必须针对查找数组的一个元素进行优化,而是针对一个数组包含另一个,与另一个相交 - 对我来说,这是违反直觉的,从大小和速度来看,这样一个广泛的解决方案对于这样一个狭窄的问题是正确的。此外,intarr扩展程序似乎仅限于int,未涵盖int64char,限制了其有用性。

3 个答案:

答案 0 :(得分:4)

您可以使用标准Postgres在任何1维数组上创建GIN索引 Details in the manual here(最后一章)。

使用 integer 数组(普通int4,而不是int2int8且没有NULL值)进行操作时{ {3}}提供了更多的运营商,通常具有卓越的性能。使用以下命令安装它(每个数据库一次)

CREATE EXTENSION intarray;

您可以在整数数组上创建GIN或GIST索引。有additional supplied module intarray
examples in the manual.需要PostgreSQL 9.1或更高版本。对于旧版本,您需要运行提供的脚本。

答案 1 :(得分:3)

传统的解决方案是在标签和对象之间使用标签表和许多标签。然后,您可以索引标记表,并通过连接将所有内容拉入单个select语句中。如果您对编程模型不满意,请查看当地友好的ORM供应商。

我无论如何都不是PostgreSQL专家,但这似乎不是一个很好的数组用例。

答案 2 :(得分:0)

这是我的解决方法,因为我看到没有PostgreSQL优化内部函数也是如此,

CREATE FUNCTION unnest_with_idx(anyarray) RETURNS 
table(idx integer, val anyelement) AS $$ 
   SELECT generate_series(1,array_upper($1,1)) as idx, unnest($1) as val;
$$ LANGUAGE SQL IMMUTABLE;
-- Test:
SELECT idx,val from unnest_with_idx(array[1,20,3,5]) as t;

如果检查是否存在内部函数,请参阅“How to acess array internal index with postgreSQL?”问题。


在@JimNasby评论后编辑

pg9.4 +

的解决方案
SELECT * FROM unnest(array[20,11,3,5]) WITH ORDINALITY;

WITH ORDINALITY生成一个新列“normalality”,即array-index。另请参阅this tutorial

pg9.5 + 中,它也适用于JSON数组!

 SELECT * FROM jsonb_array_elements( '[20,11,3,5]'::JSONB ) WITH ORDINALITY