我很难理解我认为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
答案 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)以获得所需的行为。