2014-01-17 156 views
0

我有一个表social_accounts与列facebook_id其中user_id IS NULL的部分索引。为什么Postgresql没有在IN查询中使用索引?

如果我做一个简单的查询WHERE facebook_id = '123',使用索引:

=> EXPLAIN for: SELECT "social_accounts".* FROM "social_accounts" WHERE (user_id IS NOT NULL) AND "social_accounts"."facebook_id" = '123' 
                QUERY PLAN 
-------------------------------------------------------------------------------------------------------------- 
Index Scan using index_social_accounts_on_facebook_id on social_accounts (cost=0.00..8.28 rows=1 width=345) 
    Index Cond: ((facebook_id)::text = '123'::text) 
    Filter: (user_id IS NOT NULL) 

但如果我不使用IN查询不使用索引:为什么不

=> EXPLAIN for: SELECT "social_accounts".* FROM "social_accounts" WHERE (user_id IS NOT NULL) AND "social_accounts"."facebook_id" IN ('123', '456') 
              QUERY PLAN 
--------------------------------------------------------------------------------------------------- 
Bitmap Heap Scan on social_accounts (cost=8.53..16.36 rows=2 width=345) 
    Recheck Cond: ((facebook_id)::text = ANY ('{123,456}'::text[])) 
    Filter: (user_id IS NOT NULL) 
    -> Bitmap Index Scan on index_social_accounts_on_facebook_id (cost=0.00..8.52 rows=2 width=0) 
     Index Cond: ((facebook_id)::text = ANY ('{123,456}'::text[])) 
(5 rows) 

它在第二种情况下使用索引?任何方式来加快这个查询?

(请注意,在这个例子中我已被截断的阵列,且我已经与许多更多元件但具有相同的,缓慢的,结果测试)

+2

你为什么认为它没有使用索引?它清楚地表明它使用'index_social_accounts_on_facebook_id上的位图索引扫描' –

+0

好点,我不得不承认我错过了!但是我想知道为什么Denis解释过的位图堆扫描和Recheck Cond。 – Daniel

回答

4

实际上,它是使用的索引。只是做不同的事情。

索引扫描逐一访问行,以随机顺序从一个磁盘页面到下一个磁盘页面来回访问。

位图索引扫描首先过滤要访问的磁盘页面,然后依次访问磁盘页面。重新检查cond是因为在每个页面中,您需要过滤出无效的行。

对于极少数的行,索引扫描是最便宜的。对于更多行,位图索引扫描变得最便宜。对于更多的行,seq扫描最终会变得最便宜。

+0

谢谢你的解释。非常丰富! – RKitson

相关问题