使用此架构:
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的intarr
和gist
(或gin
)索引。问题 - 对我来说 - 似乎索引是针对标准的基于pg集的数组运算符,不必须针对查找数组的一个元素进行优化,而是针对一个数组包含另一个,与另一个相交 - 对我来说,这是违反直觉的,从大小和速度来看,这样一个广泛的解决方案对于这样一个狭窄的问题是正确的。此外,intarr
扩展程序似乎仅限于int
,未涵盖int64
或char
,限制了其有用性。
答案 0 :(得分:4)
您可以使用标准Postgres在任何1维数组上创建GIN索引 Details in the manual here(最后一章)。
使用 integer
数组(普通int4
,而不是int2
或int8
且没有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评论后编辑
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