2017-02-14 20 views
0

Я должен выбрать строки в одной таблице (table_A довольно мало < строк 10K), которые не имеют соответствующих строк в другой таблице (table_B более 500K строк) на основе column_X (table_B имеет индекс, btree, on эта колонка). Если я использую следующий запрос:postgresql query plan странное поведение

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 

запрос (168 результирующие строки) выполняется примерно 600 мс. Если, с другой стороны, я попробовать другой запрос:

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 

это занимает около 8 минут, чтобы получить те же 168 строк. column_X имеет тип bigint и литье, кажется, не имеет значения (во втором запросе индекс никогда не используется). Любая идея?

+1

, пожалуйста, поделитесь результатом «EXPLAIN ANALYZE» - см. Веб-сайт https://explain.depesz.com/ для совместного использования. –

+0

Примечание: 'where column_X не является нулевым' в подзапросе не требуется. – wildplasser

+0

@wildplasser, если 'column_X' является нулевым, то он * действительно необходим. Без него, если столбец фактически содержит значение «NULL», выражение «NOT IN» (и любое выражение «IN») приведет к «NULL» (это требуется стандартом ANSI SQL). Именно поэтому PostgreSQL не превратит этот запрос в анти-соединение. – pozs

ответ

1

Подсекция NOT IN намного хуже оптимизирована, чем любая другая. Из-за разных семантических PostgreSQL нельзя использовать antijoin. Если вы можете, не используйте этот шаблон. Вместо этого используйте NOT EXISTS или внешнее соединение.