[英]How to create an index for elements of an array in PostgreSQL?
使用此架構:
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
);
一個對象可以附加任何數量的標簽。 我希望將tag_id
s保留在數組中,而不是object X tag
表,以便可以通過對象記錄輕松獲取它們。
如何在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:將結果轉換為array 。 如前所述,問題是“這實際上並未索引單個數組的值,而是索引了整個數組”
還建議使用pg的intarr
和gist
(或gin
)索引。 問題-我-看來,指數是基於集合的標准PG陣列運營商,尋找一個數組的一個元素不一定是優化的,而其中一個陣列包含另一個,另一個相交 -對我來說這是反直覺在尺寸和速度方面,如此廣泛的解決方案對於如此狹窄的問題是正確的。 另外, intarr
擴展似乎僅限於int
,不覆蓋int64
或char
,從而限制了其有用性。
您可以使用標准Postgres在任何一維數組上創建GIN索引。
手冊的詳細信息在此 (最后一章)。
當使用integer
數組(普通int4
,而不是int2
或int8
並且沒有NULL
值)進行操作時, 附加提供的模塊intarray
提供了更多的運算符,並且通常具有出色的性能。 使用以下命令安裝(每個數據庫一次):
CREATE EXTENSION intarray;
您可以在整數數組上創建GIN或GIST索引。 手冊中有示例。
CREATE EXTENSION
需要PostgreSQL 9.1或更高版本。 對於較舊的版本,您需要運行提供的腳本。
傳統的解決方案是使用標簽表,並在標簽和對象之間使用很多表。 然后,您可以為標簽表建立索引,並通過連接在單個select語句中提取所有內容。 如果您對編程模型不滿意,請咨詢當地友好的ORM供應商。
無論如何我都不是PostgreSQL專家,但這似乎不是數組的好用例。
這是我的解決方法,因為我認為沒有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評論后編輯
SELECT * FROM unnest(array[20,11,3,5]) WITH ORDINALITY;
WITH ORDINALITY
會產生一個新的列“ ordinality”,即數組索引。 另請參閱本教程 。
在pg9.5 +中 ,它也可以用於JSON數組!
SELECT * FROM jsonb_array_elements( '[20,11,3,5]'::JSONB ) WITH ORDINALITY
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.