2016-08-31 6 views
0

Ich habe eine Tabelle, die einen Index auf (Spalte A, Spalte B) hat. Und ich führe eine Abfrage aus, die wie folgt aussieht:Postgres Abfrage mit IN ist sehr langsam

SELECT * FROM table WHERE (A, B) IN ((a_1, b_1), (a_2, b_2), ..., (a_5000, b_5000)) 

Diese Abfrage ist sehr langsam! Der Plan sieht so aus:

Bitmap Heap Scan on table 
    Recheck Cond: (((A = a_1) AND (B = b_1)) OR ((A = a_2) AND (B = b_2)) OR ... 
    -> BitmapOr 
     -> Bitmap Index Scan on idx 
       Index Cond: ((A = a_1) AND (B = b_1)) 
     -> Bitmap Index Scan on idx 
       Index Cond: ((A = a_2) AND (B = b_2)) 
     ...(5000 other Bitmax Index Scan) 

Statt einen Index mit 5000 Werten scannen zu tun, Postgres tun 5000 Index-Scan mit einem Wert in einer Zeit zu sein scheint, was erklärt, warum die Abfrage so langsam ist.

Eigentlich ist es viel schneller zu tun some wie:

SELECT * FROM table WHERE A IN (a_1, ..., a_5000) 

die Ergebnisse holen und dann gefiltert werden Spalte B in der App (Python).

Ich würde wirklich bevorzugen, die Ergebnisse bereits von Postgres mit einer angemessenen Laufzeit gefiltert haben. Gibt es eine Problemumgehung?

Antwort

1

Versuchen Sie, einen CTE Beitritt:

with value_list (a,b) as (
    values 
     (a_1, b_1), 
     (a_2, b_2), ..., 
     (a_5000, b_5000) 
) 
select * 
from table t 
    join value_list v on (t.a, t.b) = (v.a, v.b); 

(Dies setzt voraus, Sie keine Duplikate in der Liste der Werte)

+0

Das ist interessant. Warum sollte es einen Unterschied machen? – zerkms

+0

@zerkms: Die Theorie (Hoffnung) ist, dass es den Optimierer trickst, einen einzigen Index-Scan für alle Werte zu machen, anstatt einen Scan für jeden Wert. –

+0

Es funktioniert! Der Planer verwendet tatsächlich nur ein Hashjoin. Ich finde es aber merkwürdig, dass der Planer nicht intelligent genug ist, um mit der ersten Frage umzugehen. –