В случай на екраниране на ?
не е възможно, можете да създадете дублиран оператор с различно име.
Нов оператор
Синтаксис за създаване на оператори в 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 ]
)
В случай на ?|
използван в jsonb
ще бъде:
CREATE OPERATOR ^|(
PROCEDURE = jsonb_exists_any,
LEFTARG = jsonb,
RIGHTARG = _text,
RESTRICT = contsel,
JOIN = contjoinsel);
Използвах ^|
като пример, алтернативно име. Може да бъде произволна последователност от този списък:+ - * / < > = ~ ! @ # % ^ & |
?`.
Можете да намерите текущата дефиниция за оператор, който ви интересува, като потърсите pg_catalog.pg_operator таблица.
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
Можете също да използвате GUI инструмент като pgAdmin и да преглеждате pg_catalog
за да подготвите SQL дефиницията за повторна употреба.
Активиране на индекс
Ако искате да използвате индекс за този "нов" оператор, ще трябва да създадете нов клас на оператора и по избор семейство. В нашия случай имаме нужда и от двете, тъй като не можем да го добавим към съществуващото семейство, тъй като операторът по подразбиране вече заема слот за стратегия.
Точно както при операторите, препоръчително е да използвате GUI инструмент като pgAdmin, за да преглеждате операторски класове и просто да го копирате и поставите.
Първо вземаме OID на оператора, който направихме дубликат:
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
Същото нещо за семейството на операторите (ще го получим от таблицата с класове на оператори), търсим клас gin, тъй като това е този, който поддържа ?|
. opcdefault
се използва, тъй като има незадължителен клас jsonb_path_ops
който не поддържа този оператор:
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
След това получаваме стратегия, използвана от оператор, който дублираме:
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
След това функции, използвани от клас:
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
Това ни отвежда до този операторен клас. Той ще създаде семейство оператори, ако вече не съществува.
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);
Сега просто трябва да създадете индекс, като използвате създаденото име на оператор, нещо като:
CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)
И трябва да можете да използвате index:
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];