jsonb у Postgres 9.4+
З новим бінарним типом даних JSON jsonbPostgres 9.4 представив значно покращені параметри індексу . Тепер ви можете мати індекс 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оператором "містить" , який може використовувати індекс 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функцій раніше були лише 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функціями.