Sql 用于在JSON数组中查找元素的索引

Sql 用于在JSON数组中查找元素的索引,sql,json,postgresql,indexing,jsonb,Sql,Json,Postgresql,Indexing,Jsonb,我有一张这样的桌子: CREATE TABLE tracks (id SERIAL, artists JSON); INSERT INTO tracks (id, artists) VALUES (1, '[{"name": "blink-182"}]'); INSERT INTO tracks (id, artists) VALUES (2, '[{"name": "The Dirty Heads"}, {"name": "Louis Richards"}]'); 还有其他几

我有一张这样的桌子:

CREATE TABLE tracks (id SERIAL, artists JSON);

INSERT INTO tracks (id, artists) 
  VALUES (1, '[{"name": "blink-182"}]');

INSERT INTO tracks (id, artists) 
  VALUES (2, '[{"name": "The Dirty Heads"}, {"name": "Louis Richards"}]');
还有其他几个专栏与这个问题无关。将它们存储为JSON是有原因的

我要做的是查找一个有特定艺术家名称(精确匹配)的曲目

我正在使用此查询:

SELECT * FROM tracks 
  WHERE 'ARTIST NAME' IN
    (SELECT value->>'name' FROM json_array_elements(artists))
比如说

SELECT * FROM tracks
  WHERE 'The Dirty Heads' IN 
    (SELECT value->>'name' FROM json_array_elements(artists))
但是,这会进行全表扫描,而且速度不是很快。我尝试使用函数
names\u as\u array(artists)
创建一个GIN索引,并使用
'ARTIST NAME'=ANY names\u as\u array(artists)
,但是没有使用索引,查询速度实际上要慢得多+ 二进制JSON数据类型大大改进了索引选项。现在,您可以直接在
jsonb
数组上创建GIN索引:

CREATE TABLE tracks (id serial, artists jsonb);  -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
不需要函数来转换数组。这将支持以下查询:

SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
是可以使用GIN索引的。(不适用于
json
,仅适用于
jsonb
!)

对索引使用更专业的非默认GIN运算符类:

CREATE INDEX tracks_artists_gin_idx ON tracks
USING  gin (artists jsonb_path_ops);  -- !
SELECT * FROM tracks
WHERE  '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
同样的问题

当前
jsonb\u path\u ops
仅支持
@>
运算符。但它通常更小更快。有更多索引选项


如果列
artists
仅包含示例中显示的名称,则将值存储为JSON文本原语将更有效,并且冗余键可以是列名

请注意JSON对象和基元类型之间的区别:

不适用于对象值,仅适用于键和数组元素

或:

CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING  gin (artistnames jsonb_path_ops);
查询:

SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
如果名称高度重复,则效率更高

Postgres 9.3中的json+ 这应适用于以下情况:

创建以下内容:

然后像这样使用查询。
WHERE
子句中的表达式必须与索引中的表达式匹配:

CREATE INDEX tracks_artists_gin_idx ON tracks
USING  gin (artists jsonb_path_ops);  -- !
SELECT * FROM tracks
WHERE  '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));

函数索引只对
不可变的
函数起作用。

这不起作用,因为返回的
SETOF
不能在索引中使用。除去它,我可以创建索引,但是查询计划器不使用它。另外,json_array_元素和array_agg都是
不可变的
@Tony:对不起,我把列名和键名混用了。修复并添加了更多内容。@PyWebDesign:jsonb包含查询通常必须与包含对象匹配相同的结构(因此在数组中搜索对象意味着必须使用数组中的对象进行查询)。数组中的基元类型有一个特殊的例外;这里有更多细节:@PyWebDesign:我现在明白了,在一个示例中缺少数组层。固定的。索引只在足够大的表中使用,以便Postgres比顺序扫描便宜。@PyWebDesign:在会话中运行
SET enable_seqscan=off(仅用于调试目的)。基于此,我提出了一个后续问题:
SELECT * FROM tracks
WHERE  '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
SELECT p.proname, p.provolatile
FROM   pg_proc p
JOIN   pg_namespace n ON n.oid = p.pronamespace
WHERE  n.nspname = 'pg_catalog'
AND    p.proname ~~* '%json%';