2014-02-28 2 views
17

Ich habe eine Postgres-Array-Spalte mit einem Gin Index:Wie fragt man ein postgres-Array mit dem GIN-Index ab?

CREATE TABLE things (
    id integer NOT NULL, 
    tags character varying(255)[] 
); 

CREATE INDEX index_things_on_tags ON things USING gin (tags); 

Es gibt ein paar Möglichkeiten, auf das Vorhandensein eines Elements in der Spalte mit verschiedenem Array-Betreiber zu überprüfen. Hier sind die, die ich gesehen habe:

  1. select * from things where 'blue' = ANY (tags)
  2. select * from things where tags <@ '{"blue"}'
  3. select * from things where '{"blue","yellow"}' && tags;

In Postgres 9.3:

  • Wird der erste den Gin Index verwenden?
  • Ich bin mir ziemlich sicher, dass der zweite den Index verwenden wird. Es unterscheidet sich jedoch von der ersten. es erlaubt mir nicht zu überprüfen, ob Blau eines der Tags ist, ich muss das genaue Array angeben. Gibt es eine Möglichkeit, den Stil der Syntax in 2 zu erreichen, was 1 erreicht?
  • In der dritten möchte ich jede Zeile, die eine von blau oder gelb hat. Wird diese Abfrage den GIN-Index verwenden? Wenn nicht, wie kann ich diese Abfrage mit einem Index machen?
+0

Führen Sie einfach 'erklären analysieren' und alle Ihre Fragen werden beantwortet –

Antwort

17

Warum nicht testen und sehen?

regress=> SET enable_seqscan = off; 
SET 

regress=> explain select * from things where 'blue' = ANY (tags); 
           QUERY PLAN         
--------------------------------------------------------------------------- 
Seq Scan on things (cost=10000000000.00..10000000037.67 rows=6 width=36) 
    Filter: ('blue'::text = ANY ((tags)::text[])) 
(2 rows) 

regress=> explain select * from things where tags <@ '{"blue"}'; 
            QUERY PLAN          
------------------------------------------------------------------------------------ 
Bitmap Heap Scan on things (cost=12.05..21.52 rows=6 width=36) 
    Recheck Cond: (tags <@ '{blue}'::character varying[]) 
    -> Bitmap Index Scan on index_things_on_tags (cost=0.00..12.05 rows=6 width=0) 
     Index Cond: (tags <@ '{blue}'::character varying[]) 
(4 rows) 

regress=> explain select * from things where '{"blue","yellow"}' && tags; 
            QUERY PLAN          
------------------------------------------------------------------------------------- 
Bitmap Heap Scan on things (cost=12.10..22.78 rows=12 width=36) 
    Recheck Cond: ('{blue,yellow}'::character varying[] && tags) 
    -> Bitmap Index Scan on index_things_on_tags (cost=0.00..12.09 rows=12 width=0) 
     Index Cond: ('{blue,yellow}'::character varying[] && tags) 
(4 rows) 

So ist Pg den Index für die && und <@ Abfragen mit, aber nicht für = ANY (...).

Ich bin mir sicher, dass es möglich wäre, Pg zu lehren, x = ANY (y) in ARRAY[x] @> y zu transformieren, aber das tut es im Moment nicht.

Was 2 tut ist genau das, was Sie sagen, Sie wollen. Testen Sie, ob "blau" eines der Tags ist. Es ist kein Gleichheitstest, es ist ein Mitgliedschaftstest.

+1

Vielen Dank! Ich war nicht vertraut mit 'SET enable_seqscan = off;', um die Indexnutzung auf kleinen Daten zu testen. –

+0

Hier ist, was ich über das Verhalten von 2 beobachte: https://gist.github.com/jjb/9281339 –

+2

@JohnBachir Reverse it; '@>'. BTW, http://sqlfiddle.com/ ist viel nützlicher für diese Art von Sache. –

Verwandte Themen