jsonb
在 Postgres 9.4+
二进制 JSON 数据类型jsonb
在很大程度上改进了索引选项。您现在可以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"}]';
@>
是jsonb
“包含”运算符,可以使用 GIN 索引。(不为json
,只为jsonb
!)
或者jsonb_path_ops
您对索引使用更专业的非默认 GIN 运算符类:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
相同的查询。
目前jsonb_path_ops
只支持@>
运营商。但它通常更小更快。有更多的索引选项,手册中有详细说明。
如果列artists
仅包含示例中显示的名称,则仅将值存储为 JSON 文本原语会更有效,冗余键可以是列名。
注意 JSON 对象和原始类型之间的区别:
CREATE TABLE tracks (id serial, artistnames jsonb);
INSERT INTO tracks VALUES (2, '["The Dirty Heads", "Louis Richards"]');
CREATE INDEX tracks_artistnames_gin_idx ON tracks USING gin (artistnames);
询问:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
不适用于对象值,仅适用于键和数组元素。
或者:
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
询问:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
如果名称高度重复,则效率更高。
json
在 Postgres 9.3+
这应该与一个IMMUTABLE
功能一起使用:
CREATE OR REPLACE FUNCTION json2arr(_j json, _key text)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT elem->>_key FROM json_array_elements(_j) elem)';
创建此功能索引:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
并使用这样的查询。子句中的表达式WHERE
必须与索引中的表达式匹配:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
更新了评论中的反馈。我们需要使用数组运算符来支持 GIN 索引。
在这种情况下, “被包含”运算符<@
。
函数波动的注意事项
IMMUTABLE
即使json_array_elements()
不是,您也可以声明您的函数。
大多数JSON
功能曾经是 only STABLE
,不是IMMUTABLE
。在黑客名单上进行了讨论以改变这一点。现在大部分都是IMMUTABLE
。检查:
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%';
功能索引仅适用于IMMUTABLE
功能。