jsonb
i Postgres 9.4+
Den binära JSON-datatypen jsonb
förbättrar till stor del indexalternativ. Du kan nu ha ett GIN-index på en jsonb
array direkt:
CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Inget behov av en funktion för att konvertera arrayen. Detta skulle stödja en fråga:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
är jsonb
"innehåller" operator, som kan använda GIN-index. (Inte för json
, endast jsonb
!)
Eller du använder den mer specialiserade, icke-standardiserade GIN-operatörsklassen jsonb_path_ops
för indexet:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Samma fråga.
För närvarande jsonb_path_ops
stöder endast @>
operatör. Men det är vanligtvis mycket mindre och snabbare. Det finns fler indexalternativ, detaljer i manualen .
Om kolumnen artists
innehåller bara namn som visas i exemplet, det skulle vara mer effektivt att lagra bara värdena som JSON-text primitiver och den redundanta nyckeln kan vara kolumnnamnet.
Notera skillnaden mellan JSON-objekt och primitiva typer:
- Använda index i json-arrayen 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);
Fråga:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
fungerar inte för objektets värden , bara nycklar och matriselement .
Eller:
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Fråga:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
Mer effektivt om namn är mycket duplicerade.
json
i Postgres 9.3+
Detta bör fungera 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)';
Skapa detta funktionella index :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
Och använd en fråga så här. Uttrycket i WHERE
satsen måste matcha den i indexet:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Uppdaterad med feedback i kommentarer. Vi måste använda matrisoperatorer för att stödja GIN-index.
Operatorn "innehålls av" <@
i det här fallet.
Anmärkningar om funktionsvolatilitet
Du kan deklarera din funktion IMMUTABLE
även om json_array_elements()
är inte var det inte.
De flesta JSON
funktioner brukade bara vara STABLE
, inte IMMUTABLE
. Det fanns en diskussion på hackerlistan för att ändra på det. De flesta är IMMUTABLE
nu. Kolla 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%';
Funktionella index fungerar bara med IMMUTABLE
funktioner.