3

使用此架构:

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我希望将s 保留在一个数组中,而不是一个表,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_ids 数组保留在一列中并省去交叉表和array_agg()

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

还建议使用 pgintarrgist(或gin)索引。问题 - 对我来说 - 似乎索引是针对标准 pg 基于集合的数组运算符,不一定针对查找数组的一个元素进行优化,而是在一个数组包含另一个元素的位置与另一个数组相交- 对我来说这是违反直觉的也就是说,从规模和速度方面来看,如此广泛的解决方案对于如此狭窄的问题是正确的。此外,intarr扩展名似乎仅限于int,不包括int64char,限制了它的有用性。

4

3 回答 3

6

您可以使用标准 Postgres 在任何一维数组上创建 GIN 索引。
此处手册中的详细信息(最后一章)。

在使用integer数组(plain int4、notint2int8noNULL值)进行操作时,额外提供的模块intarray提供了更多的操作符,并且通常具有卓越的性能。安装它(每个数据库一次):

CREATE EXTENSION intarray;

您可以在整数数组上创建 GIN 或 GIST 索引。手册中有示例。
CREATE EXTENSION需要 PostgreSQL 9.1 或更高版本。对于旧版本,您需要运行提供的脚本。

于 2012-06-03T05:35:09.567 回答
2

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

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

于 2012-06-03T03:15:22.663 回答
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;

要检查是否存在内部函数,请参阅“如何使用 postgreSQL 访问数组内部索引? ”问题。


在@JimNasby 评论后编辑

pg9.4+的解决方案

SELECT * FROM unnest(array[20,11,3,5]) WITH ORDINALITY;

生成WITH ORDINALITY 一个新列“序数”,即数组索引。另请参阅本教程

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

 SELECT * FROM jsonb_array_elements( '[20,11,3,5]'::JSONB ) WITH ORDINALITY
于 2012-09-03T12:23:30.027 回答