jsonb в Postgres 9.4+
Двоичният тип данни JSON jsonb до голяма степен подобрява опциите за индекси. Вече можете да имате GIN индекс на jsonb масив директно:
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" оператор, който може да използва GIN индекса. (Не за json , само jsonb !)
Или използвате по-специализирания клас на оператор GIN, който не е по подразбиране jsonb_path_ops за индекса:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Същата заявка.
В момента jsonb_path_ops поддържа само @> оператор. Но обикновено е много по-малък и по-бърз. Има още опции за индекси, подробности в ръководството .
Ако колоната artists съдържа само имена, както е показано в примера, би било по-ефективно да се съхраняват само стойностите като JSON текстови примитиви и излишния ключ може да бъде името на колоната.
Обърнете внимание на разликата между JSON обекти и примитивни типове:
- Използване на индекси в json масив в PostgreSQL
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 функциите са били само 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 функции.