jsonb
i Postgres 9.4+
Den binære JSON-datatype jsonb
forbedrer i høj grad indeksmuligheder. Du kan nu have et GIN-indeks på en jsonb
array direkte:
CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Der er ikke behov for en funktion til at konvertere arrayet. Dette ville understøtte en forespørgsel:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
er jsonb
"indeholder" operator, som kan bruge GIN-indekset. (Ikke til json
, kun jsonb
!)
Eller du bruger den mere specialiserede, ikke-standard GIN-operatørklasse jsonb_path_ops
for indekset:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Samme forespørgsel.
I øjeblikket jsonb_path_ops
understøtter kun @>
operatør. Men det er typisk meget mindre og hurtigere. Der er flere indeksmuligheder, detaljer i manualen .
Hvis kolonnen artists
indeholder kun navne som vist i eksemplet, det ville være mere effektivt kun at gemme værdierne som JSON-tekst primitiver og den redundante nøgle kan være kolonnenavnet.
Bemærk forskellen mellem JSON-objekter og primitive typer:
- Brug af indekser i json-array i 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);
Forespørgsel:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
virker ikke for objektets værdier , kun nøgler og array-elementer .
Eller:
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Forespørgsel:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
Mere effektivt, hvis navne er meget duplikative.
json
i Postgres 9.3+
Dette burde fungere med en IMMUTABLE
funktion :
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)';
Opret dette funktionelle indeks :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
Og brug en forespørgsel sådan her. Udtrykket i WHERE
klausul skal matche den i indekset:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Opdateret med feedback i kommentarer. Vi skal bruge array-operatorer for at understøtte GIN-indekset.
Operatøren "er indeholdt af" <@
i dette tilfælde.
Bemærkninger om funktionsvolatilitet
Du kan erklære din funktion IMMUTABLE
selvom json_array_elements()
er det ikke var det ikke.
De fleste JSON
funktioner plejede kun at være STABLE
, ikke IMMUTABLE
. Der var en diskussion på hackerlisten for at ændre det. De fleste er IMMUTABLE
nu. Tjek med:
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%';
Funktionelle indekser virker kun med IMMUTABLE
funktioner.