2017-02-14 7 views
0

Ich muss die Zeilen in einer Tabelle (table_A ziemlich klein < 10K Zeilen), die keine entsprechenden Zeilen in einer anderen Tabelle (table_B über 500K Zeilen) basierend auf column_X (table_B hat einen Index, btree, auf diese Spalte). Wenn ich die folgende Abfrage:Postgresql Abfrage Plan seltsames Verhalten

select a.column1, 
    a.column2, 
    a.column3, 
    a.column_X, 
    b.column_X 
from table_A a 
left outer join table_B b on a.column_X = b.column_X 
where a.column_X <> 0 
    and b.column_X is null 

die Abfrage (168 resultierende Zeilen) in etwa 600 ms ausgeführt wird. Wenn auf der anderen Seite, ich versuche eine andere Abfrage:

select column1, 
    column2, 
    column3, 
    column_X 
from table_A 
where column_X not in (
     select column_X 
     from table_B 
     where column_X is not null 
     ) 
    and column_X <> 0 

es etwa 8 Minuten dauert die gleichen 168 Zeilen abzurufen. column_X ist vom Typ bigint und casting scheint keinen Unterschied zu machen (in der zweiten Abfrage wird der Index nie benutzt). Irgendeine Idee?

+1

bitte teilen 'EXPLAIN ANALYZE' Ergebnis - siehe das Web https://explain.depesz.com/ zum Teilen. –

+0

Hinweis: Das 'where column_X ist nicht null 'in der Unterabfrage wird nicht benötigt. – wildplasser

+0

@wildplasser Wenn 'column_X' nullable ist, dann ist * * wirklich erforderlich. Ohne sie würde, wenn die Spalte tatsächlich einen "NULL" -Wert enthält, der "NOT IN" -Ausdruck (und jeder "IN" -Ausdruck) zu "NULL" führen (dies wird vom ANSI-SQL-Standard benötigt). Und genau deshalb wird PostgreSQL diese Anfrage nicht in einen Anti-Join verwandeln. – pozs

Antwort

1

Der NOT IN Subselect ist viel schlechter optimiert als jeder andere. Aufgrund unterschiedlicher semantischer PostgreSQL kann Anti-Join nicht verwendet werden. Wenn Sie können, verwenden Sie dieses Muster nicht. Verwenden Sie stattdessen NOT EXISTS oder Outer Join.