Ich habe eine sehr einfache JSON-Tabelle, die ich mit einigen Beispieldaten fülle:
CREATE TABLE jsonthings(d JSONB NOT NULL);
INSERT INTO jsonthings VALUES ('{"name":"First","tags":["foo"]}');
INSERT INTO jsonthings VALUES ('{"name":"Second","tags":["foo","bar"]}');
INSERT INTO jsonthings VALUES ('{"name":"Third","tags":["bar","baz"]}');
INSERT INTO jsonthings VALUES ('{"name":"Fourth","tags":["baz"]}');
CREATE INDEX ON jsonthings USING GIN(d);
Und ich versuche, den Index beim Ausführen von a zu verwenden SELECT
. Ein einfaches SELECT
Abrufen der Zeilen, in denen der Wert ein einzelnes Element ist, funktioniert einwandfrei:
SELECT d FROM jsonthings WHERE d @> '{"name":"First"}';
Wenn name
ich jedoch versuche, eine Abfrage auszuführen, die mehr als einem Wert von entspricht, kann ich nicht herausfinden, wie der Index verwendet wird. Ich habe es versucht:
SELECT d FROM jsonthings WHERE d->>'name' = ANY(ARRAY['First', 'Second']);
SELECT d FROM jsonthings WHERE d->'name' ?| ARRAY['First', 'Second'];
SELECT d FROM jsonthings WHERE d#>'{name}' ?| ARRAY['First','Second'];
und alle zeigen einen sequentiellen Scan der Tabelle (ich verwende enable_seqscan=false
, um die Indexverwendung zu erzwingen, wenn möglich). Gibt es eine Möglichkeit, die Abfrage so umzuschreiben, dass sie einen Index verwendet? Mir ist bewusst, dass ich Folgendes tun könnte:
SELECT * FROM jsonthings WHERE d @> '{"name":"First"}' OR d @> '{"name":"Second"}';
Aber dann habe ich eine Abfrage mit variabler Länge und gehe durch JDBC, sodass die Vorteile der Abfrage als PreparedStatement verloren gehen.
Ich bin auch daran interessiert, eine ähnliche Abfrage für eine Reihe von Elementen im tags
Schlüssel zu sehen, z.
SELECT d FROM jsonthings WHERE d @> '{"tags":["foo"]}' OR d @> '{"tags":["bar"]}';
aber unter Verwendung einer ARRAY
statt mehrerer Bedingungen und unter Verwendung eines Index.
Dies ist auf PostgreSql 9.4.
Antworten:
Versuchen Sie in Dokumenten ( http://www.postgresql.org/docs/9.4/static/datatype-json.html ), den Ausdrucksindex zu verwenden:
quelle
SELECT d FROM jsonthings WHERE d->'name' ?| ARRAY['First', 'Second'];
sonst wird der Index nicht verwendet. Vielen Dank.Dies ist eine Antwort auf die Antwort von Mladen. Ich habe nicht genug Ruf, um einen Kommentar zu hinterlassen, aber ich wollte antworten, weil es so aussieht, als ob die Abfrage falsch ist und mich verwirrt hat und andere Leute in Zukunft verwirren könnte.
Sie erwähnen die Verwendung von:
Um Einträge abzurufen, die entweder
First
oderSecond
als Namen haben, scheint dies für mich jedoch nicht zu funktionierenPostgreSQL 9.4.4
:Anscheinend versucht die obige Abfrage, Einträge abzurufen, bei denen das
name
Attribut das Array enthält["First", "Second"]
.Wenn ich einen solchen Eintrag erstelle:
Versuchen Sie die Abfrage erneut, und es wird ein Ergebnis zurückgegeben:
Dies unterscheidet sich jedoch von der Frage des Originalplakats, wie ein Index verwendet werden soll, wenn Einträge abgefragt werden, bei denen das
name
Attribut entwederFirst
oder warSecond
:Ich wollte dies hier bereitstellen, damit andere Leute nicht glauben, dass es möglich ist, eine ODER- Abfrage mit JSON durch Bereitstellen durchzuführen
"name": ["First", "Second"]
, da dies irreführend ist.quelle