PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Индекс за намиране на елемент в JSON масив

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 функции.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. DBConcurrency изключение, възникнало при актуализиране с помощта на Dataadapter

  2. Как да форматирате числата като валута в PostgreSQL

  3. Извличане на последната известна стойност за всяка колона от ред

  4. Изпълнете заявки на PostgreSQL от командния ред

  5. как мога да създам нов XML файл от съществуваща база данни в PostgreSQL база данни с помощта на java