Postgres使用Index vs Seq Scan不一致

时间:2015-03-13 19:38:30

标签: sql postgresql

我很难理解我认为postgres选择使用指数的不一致之处。我们根据NOT IN对postgres按顺序执行的索引列进行查询,但是当我们执行与IN相同的查询时,它会使用索引。

我创建了一个简单的示例,我相信它会演示此问题,请注意第一个查询是顺序的

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那么简单)。

我们在CentOS 6.6上使用Postgres 9.2

1 个答案:

答案 0 :(得分:0)

PostgreSQL会在有意义的时候使用Index。统计数据可能表明你的NOT IN有太多的元组无法返回以使索引有效。

您可以通过执行以下操作来测试:

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

结果将告诉您PostgreSQL是否做出了正确的决定。如果不是,您可以调整列的统计信息和成本(random_page_cost)以获得所需的行为。