sql >> Databáze >  >> RDS >> PostgreSQL

Index pro nalezení prvku v poli JSON

jsonb v Postgres 9.4+

Binární datový typ JSON jsonb do značné míry zlepšuje možnosti indexu. Nyní můžete mít index GIN na jsonb pole přímo:

CREATE TABLE tracks (id serial, artists jsonb);  -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);

Není potřeba funkce pro převod pole. To by podporovalo dotaz:

SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';

@> je jsonb operátor "obsahuje", který může používat index GIN. (Ne pro json , pouze jsonb !)

Nebo používáte specializovanější, nevýchozí třídu operátorů GIN jsonb_path_ops pro index:

CREATE INDEX tracks_artists_gin_idx ON tracks
USING  gin (artists jsonb_path_ops);  -- !

Stejný dotaz.

Aktuálně jsonb_path_ops podporuje pouze @> operátor. Ale obvykle je mnohem menší a rychlejší. Existuje více možností indexu, podrobnosti v příručce .

Pokud sloupec artists obsahuje pouze názvy zobrazené v příkladu, bylo by efektivnější ukládat pouze hodnoty jako primitiva textu JSON a redundantní klíč může být název sloupce.

Všimněte si rozdílu mezi objekty JSON a primitivními typy:

  • Použití indexů v poli json v 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);

Dotaz:

SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';

? nefunguje pro objektové hodnoty , stačí klávesy a prvky pole .

Nebo:

CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING  gin (artistnames jsonb_path_ops);

Dotaz:

SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;

Efektivnější, pokud jsou názvy vysoce duplicitní.

json v Postgres 9.3+

To by mělo fungovat s IMMUTABLE funkce :

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)';

Vytvořte tento funkční index :

CREATE INDEX tracks_artists_gin_idx ON tracks
USING  gin (json2arr(artists, 'name'));

A použijte dotaz takhle. Výraz v WHERE klauzule se musí shodovat s klauzulí v indexu:

SELECT * FROM tracks
WHERE  '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));

Aktualizováno o zpětnou vazbu v komentářích. Musíme použít operátory pole pro podporu indexu GIN.
Operátor "je obsažen v" <@ v tomto případě.

Poznámky k volatilitě funkcí

Svou funkci můžete prohlásit za IMMUTABLE i když json_array_elements() není nebyl.
Většina JSON funkce byly dříve pouze STABLE , nikoli IMMUTABLE . Na seznamu hackerů proběhla diskuse, která to měla změnit. Většina z nich je IMMUTABLE Nyní. Zkontrolujte pomocí:

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%';

Funkční indexy fungují pouze s IMMUTABLE funkce.




  1. Jak přesunout pole v mřížce dotazů v aplikaci Access

  2. SQL Server TempDB Monitoring pomocí Dynamic Management Views (DMV)

  3. PARSE() vs TRY_PARSE() v SQL Server:Jaký je rozdíl?

  4. Formátování DATE v oracle