PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

So umgehen Sie das Fragezeichen (?) mit Spring JpaRepository

Falls ? maskiert wird ist nicht möglich, Sie können doppelte Operatoren mit unterschiedlichen Namen erstellen.

Neuer Operator

Syntax zum Erstellen von Operatoren in 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 ]
)

Im Falle von ?| verwendet in jsonb es wird sein:

CREATE OPERATOR ^|(
  PROCEDURE = jsonb_exists_any,
  LEFTARG = jsonb,
  RIGHTARG = _text,
  RESTRICT = contsel,
  JOIN = contjoinsel);

Ich habe ^| verwendet als Beispiel alternativer Name. Es kann eine beliebige Folge aus dieser Liste sein:+ - * / < > = ~ ! @ # % ^ & | ?`.

Sie können die aktuelle Definition für den Sie interessierenden Operator finden, indem Sie die Tabelle pg_catalog.pg_operator abfragen.

SELECT oid, *
  FROM pg_catalog.pg_operator
 WHERE oprname = '?|'
   AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');

Sie können auch GUI-Tools wie pgAdmin verwenden und pg_catalog durchsuchen um die SQL-Definition für die Wiederverwendung vorzubereiten.

Index aktivieren

Wenn Sie den Index für diesen „neuen“ Operator verwenden möchten, müssen Sie eine neue Operatorklasse und optional eine Familie erstellen. In unserem Fall benötigen wir beides, da wir es nicht zu einer bestehenden Familie hinzufügen können, da der Standardoperator bereits einen Strategieplatz belegt.

Genau wie bei Operatoren wird empfohlen, ein GUI-Tool wie pgAdmin zu verwenden, um Operatorklassen zu durchsuchen und sie einfach zu kopieren und einzufügen.

Zuerst nehmen wir die OID des Operators, von dem wir ein Duplikat erstellt haben:

SELECT oid, *
  FROM pg_catalog.pg_operator
 WHERE oprname = '?|'
   AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');

Das Gleiche gilt für die Operatorfamilie (wir werden sie stattdessen aus der Operatorklassentabelle erhalten), wir suchen nach der Gin-Klasse, da diese diejenige ist, die ?| unterstützt . opcdefault wird verwendet, weil es die optionale Klasse jsonb_path_ops gibt die diesen Operator nicht unterstützt:

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

Dann erhalten wir die Strategie, die von dem Operator verwendet wird, den wir dupliziert haben:

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

Dann Funktionen, die von der Klasse verwendet werden:

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

Damit kommen wir zu dieser Operatorklasse. Es wird eine Operatorfamilie erstellt, falls sie noch nicht existiert.

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);

Jetzt müssen Sie nur noch einen Index mit dem erstellten Operatornamen erstellen, etwa so:

CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)

Und Sie sollten index:

verwenden können
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];