Ich bin ziemlich neu in Postgres und zur Zeit 9.6 verwenden. Beim Versuch, eine Volltextsuche in Postgres mit seinen Jsonb-Dokumenten zu implementieren, bemerkte ich langsame Suchergebnisse für verschachtelte Arrays. Ich habe den Befehl 'explain' verwendet und keine Indizes verwendet. Der Einfachheit halber Zweck habe ich eine Tabelle zu untersuchen:Index für verschachtelte Suche JSONB Array-Elemente in PostgreSQL
CREATE TABLE book (
id BIGSERIAL NOT NULL,
data JSONB NOT NULL
);
Meine verfügbaren Indizes:
CREATE INDEX book_author_idx
ON book USING GIN (to_tsvector('english', book.data ->> 'author'));
CREATE INDEX book_author_name_idx
ON book USING GIN (to_tsvector('english', book.data -> 'author' ->> 'name'));
Und einige Daten, ein Dokument zu füllen:
INSERT INTO book (data)
VALUES (CAST('{"author": [{"id": 0, "name": "Cats"}, ' ||
' {"id": 1, "name": "Dogs"}]}' AS JSONB));
ich in der Lage bin zu suchen Bei Buchelementen, die die folgende Abfrage verwenden, wird jedoch kein Index verwendet. Mit meinen tatsächlichen Daten von 120k Produkten dauert es etwa 1200ms, während andere Suchen mit einem Index 0,2ms dauern.
EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book, jsonb_array_elements(data #> '{author}') author_array
WHERE to_tsvector('english', author_array ->> 'name') @@ to_tsquery('cat');
Kontrast In der nächsten Abfrage verwendet die book_author_name_idx aber wegen der Arraystruktur nichts finden.
EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book
WHERE to_tsvector('english', data -> 'author' ->> 'name') @@ to_tsquery('cat');
Wie kann ich meine Abfrage optimieren, um einen Sprachenindex zu verwenden? Ich bin mir bewusst, dass ich eine neue Tabelle für Autoren erstellen und nur die IDs referenzieren könnte, aber ich würde lieber alle Daten in einer Tabelle für die Leistung halten.
Verwendung 'UNNEST()' und seine Freunde (Ergebnis-Satz Funktionen produzieren, wie 'jsonb_array_elements()') in einem 'LATERAL JOIN' verhindert die Verwendung von einem Index (zumindest auf Eigenschaften von ihnen berechnet). Wenn Sie bei dieser Struktur bleiben, müssen Sie eine benutzerdefinierte 'IMMUTABLE' -Funktion erstellen, um' Tsvector'-Werte aus Ihrer 'jsonb'-Spalte zu erzeugen und diese Funktion sowohl in Ihrem Index als auch in Ihrer Abfrage zu verwenden. – pozs
Der interessante Teil darin ist die Tatsache, dass 'tsvector' keine eingebaute Aggregation hat, also müssen Sie entweder 1) Aggregate als Strings aggregieren (mit einer Grundregel) 2) eine benutzerdefinierte Aggregation für' tsvector' 3 erstellen) Verwenden Sie einen cleveren rekursiven CTE (weil für sie bereits eine Verkettung existiert). – pozs