En cas d'échappement de ?
n'est pas possible, vous pouvez créer un opérateur en double avec un nom différent.
Nouvel opérateur
Syntaxe pour créer des opérateurs dans Postgres :
CREATE OPERATOR name (
PROCEDURE = function_name
[, LEFTARG = left_type ] [, RIGHTARG = right_type ]
[, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
[, RESTRICT = res_proc ] [, JOIN = join_proc ]
[, HASHES ] [, MERGES ]
)
En cas de ?|
utilisé dans jsonb
ce sera :
CREATE OPERATOR ^|(
PROCEDURE = jsonb_exists_any,
LEFTARG = jsonb,
RIGHTARG = _text,
RESTRICT = contsel,
JOIN = contjoinsel);
J'ai utilisé ^|
par exemple, nom alternatif. Il peut s'agir de n'importe quelle séquence de cette liste :+ - * / < > = ~ ! @ # % ^ & |
?`.
Vous pouvez trouver la définition actuelle de l'opérateur qui vous intéresse en interrogeant la table pg_catalog.pg_operator.
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
Vous pouvez également utiliser un outil graphique comme pgAdmin et parcourir pg_catalog
pour que la définition SQL soit prête à être réutilisée.
Activation de l'index
Si vous souhaitez utiliser l'index pour ce "nouveau" opérateur, vous devrez créer une nouvelle classe d'opérateur et éventuellement une famille. Dans notre cas, nous avons besoin des deux, car nous ne pouvons pas l'ajouter à la famille existante, car l'opérateur par défaut prend déjà l'emplacement stratégique.
Tout comme avec les opérateurs, il est recommandé d'utiliser un outil graphique comme pgAdmin pour parcourir les classes d'opérateurs et simplement copier-coller.
Tout d'abord, nous prenons l'OID de l'opérateur dont nous avons fait un doublon :
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
Même chose pour la famille d'opérateurs (nous l'obtiendrons plutôt à partir de la table des classes d'opérateurs), nous recherchons la classe gin car c'est celle qui prend en charge ?|
. opcdefault
est utilisé, car il existe une classe facultative jsonb_path_ops
qui ne prend pas en charge cet opérateur :
SELECT opcfamily
FROM pg_opclass
WHERE opcintype = (SELECT oid FROM pg_type WHERE typname = 'jsonb')
AND opcmethod = (SELECT oid FROM pg_am WHERE amname = 'gin')
AND opcdefault
Ensuite, nous obtenons la stratégie utilisée par l'opérateur que nous avons dupliqué :
SELECT amopstrategy,
(SELECT typname FROM pg_type WHERE oid = amoplefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amoprighttype) AS right_t,*
FROM pg_amop
WHERE amopfamily = 4036 --family oid
AND amopopr = 3248 --operator oid
Ensuite les fonctions utilisées par classe :
SELECT amprocnum, amproc::text, pg_get_function_identity_arguments(amproc::oid) AS args,
(SELECT typname FROM pg_type WHERE oid = amproclefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amprocrighttype) AS right_t,*
FROM pg_amproc
WHERE amprocfamily = 4036 --op family
Cela nous amène à cette classe d'opérateurs. Il créera une famille d'opérateurs si elle n'existe pas déjà.
CREATE OPERATOR CLASS jsonb_ops_custom
FOR TYPE jsonb USING gin AS
OPERATOR 10 ^|(jsonb, _text),
FUNCTION 1 gin_compare_jsonb(text, text),
FUNCTION 2 gin_extract_jsonb(jsonb, internal, internal),
FUNCTION 3 gin_extract_jsonb_query(jsonb, internal, smallint, internal, internal, internal, internal),
FUNCTION 4 gin_consistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal, internal),
FUNCTION 6 gin_triconsistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal);
Il ne vous reste plus qu'à créer un index en utilisant le nom de l'opérateur qui a été créé, quelque chose comme :
CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)
Et vous devriez pouvoir utiliser index :
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];