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 "contains" operator,可以使用GIN索引。 (不适用于json,仅适用于jsonb!)
或者你使用更专业的、非默认的 GIN 操作符类jsonb_path_ops 作为索引:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
相同的查询。
目前jsonb_path_ops 仅支持@> 运算符。但它通常更小更快。还有更多索引选项,details in the manual。
如果列 artists 仅包含示例中显示的名称,则仅将 值 存储为 JSON 文本会更有效primitives 和多余的 key 可以是列名。
注意 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';
? 不适用于对象 values,仅适用于 keys 和 数组元素。
或者:
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 function:
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)';
创建这个functional index:
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'));
更新了 cmets 中的反馈。我们需要使用array operators来支持GIN索引。
在这种情况下为"is contained by" operator <@。
关于函数波动性的说明
即使json_array_elements() 不是 不是,你也可以声明你的函数IMMUTABLE。
大多数JSON 函数过去只有STABLE,而不是IMMUTABLE。 There was a discussion on the hackers list to change that. 现在大部分是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 函数。