2015-03-13 3 views
1

Мне трудно понять, что я воспринимаю как несоответствие в том, как postgres выбирают использовать индексы. У нас есть запрос на основе NOT IN против индексированного столбца, который postgres выполняется последовательно, но когда мы выполняем тот же запрос, что и IN, он использует индекс.Postgres противоречивое использование индекса против Seq Scan

Я создал упрощенный пример, который я считаю, демонстрирует этот вопрос, обратите внимание на этот первый запрос является последовательным

CREATE TABLE node 
(
    id SERIAL PRIMARY KEY, 
    vid INTEGER 
); 
CREATE INDEX x ON node(vid); 

INSERT INTO node(vid) VALUES (1),(2); 

EXPLAIN ANALYZE 
SELECT * 
FROM node 
WHERE NOT vid IN (1); 

Seq Scan on node (cost=0.00..36.75 rows=2129 width=8) (actual time=0.009..0.010 rows=1 loops=1) 
    Filter: (vid <> 1) 
    Rows Removed by Filter: 1 
Total runtime: 0.025 ms 

Но если инвертировать запрос к IN, вы заметите, что теперь решили использовать индекс

EXPLAIN ANALYZE 
SELECT * 
FROM node 
WHERE vid IN (2); 

Bitmap Heap Scan on node (cost=4.34..15.01 rows=11 width=8) (actual time=0.017..0.017 rows=1 loops=1) 
    Recheck Cond: (vid = 1) 
    -> Bitmap Index Scan on x (cost=0.00..4.33 rows=11 width=0) (actual time=0.012..0.012 rows=1 loops=1) 
     Index Cond: (vid = 1) 
Total runtime: 0.039 ms 

Может ли кто-нибудь пролить свет на это? В частности, существует способ переписать NOT IN для работы с индексом (когда, очевидно, набор результатов не так упрощен, как только 1 или 2).

Мы используем Postgres 9.2 на CentOS 6.6

+0

Что произойдет, если вы напишете: 'WHERE vid NOT IN (1)'? –

+0

Это была хорошая мысль, но, к сожалению, это не имело значения. Каким-то образом 'NOT IN' является не просто обратным« IN »с точки зрения планировщиков. – user590028

+0

'Как-то НЕ IN - это не просто обратное к IN с точки зрения планировщиков': это правильно, так как vid NULLable. – wildplasser

ответ

0

PostgreSQL собирается использовать индекс, когда это имеет смысл. Вероятно, статистика показывает, что ваш NOT IN имеет слишком много кортежей, чтобы вернуться, чтобы сделать индекс эффективным.

Вы можете проверить это, выполнив следующие действия:

set enable_seqscan to false; 
explain analyze .... NOT IN 
set enable_seqscan to true; 
explain analyze .... NOT IN 

Результаты покажет вам, если PostgreSQL делает правильное решение. Если это не так, вы можете внести коррективы в статистику столбца и/или затраты (random_page_cost), чтобы получить желаемое поведение.

+0

В приведенном выше примере таблица имеет ровно две строки, одну строку где vid = 1 и где где vid = 2. 'IN' и' NOT IN' должны давать одно и то же решение, нет? – user590028

+0

Нет, потому что планировщик обнаруживает, что в два раза больше IN IN IN, вкратце, это будет быстрее seqscan для этих двух строк, чем для индекса, чтобы получить указатель и вернуться к странице в таблице, чтобы потяните ряды. –

+0

Я не понимаю этот комментарий. Таблица имеет две строки. Каждый запрос возвращает только одну строку. – user590028

Смежные вопросы