jsonb
in Postgres 9.4+
Het binaire JSON-gegevenstype jsonb
verbetert de indexopties grotendeels. U kunt nu een GIN-index hebben op een jsonb
direct array:
CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Er is geen functie nodig om de array te converteren. Dit zou een vraag ondersteunen:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
zijnde de jsonb
"bevat" operator, die de GIN-index kan gebruiken. (Niet voor json
, alleen jsonb
!)
Of u gebruikt de meer gespecialiseerde, niet-standaard GIN-operatorklasse jsonb_path_ops
voor de index:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Zelfde vraag.
Momenteel jsonb_path_ops
ondersteunt alleen de @>
exploitant. Maar het is meestal veel kleiner en sneller. Er zijn meer indexopties, details in de handleiding .
Als de kolom artists
bevat alleen namen zoals weergegeven in het voorbeeld, het zou efficiënter zijn om alleen de waarden op te slaan als JSON-tekst primitieven en de overbodige sleutel kan de kolomnaam zijn.
Let op het verschil tussen JSON-objecten en primitieve typen:
- Indexen gebruiken in json-array in 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);
Vraag:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
werkt niet voor object waarden , gewoon toetsen en array-elementen .
Of:
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Vraag:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
Efficiënter als namen zeer dubbel zijn.
json
in Postgres 9.3+
Dit zou moeten werken met een IMMUTABLE
functie :
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)';
Maak deze functionele index :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
En gebruik een query zoals dit. De uitdrukking in de WHERE
clausule moet overeenkomen met die in de index:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Bijgewerkt met feedback in opmerkingen. We moeten matrixoperatoren . gebruiken ter ondersteuning van de GIN-index.
De operator "is bevat door" <@
in dit geval.
Opmerkingen over functievolatiliteit
U kunt uw functie IMMUTABLE
. declareren zelfs als json_array_elements()
is niet was niet.
De meeste JSON
functies waren voorheen alleen STABLE
, niet IMMUTABLE
. Er was een discussie over de hackerslijst om daar verandering in te brengen. De meeste zijn IMMUTABLE
nu. Controleer met:
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%';
Functionele indexen werken alleen met IMMUTABLE
functies.