Rails 3 Postgres使用单字段索引进行查询,但不应该使用复合索引吗?

时间:2014-01-10 01:46:52

标签: ruby database ruby-on-rails-3 postgresql indexing

因此User有许多:orders,其效果与您预期的一样。我还有一个valid范围的订单,应通过确保订单处于一组列入白名单的状态(例如,未取消订单)进行过滤。

我在订单表上声明了一些索引,我的schema.rb看起来像:

add_index "orders", ["state"], :name => "index_orders_on_state"
add_index "orders", ["user_id", "state"], :name => "index_orders_on_user_id_and_state"
add_index "orders", ["user_id"], :name => "index_orders_on_user_id"

当我运行puts user.orders.valid.explain时,我明白了:

EXPLAIN for: SELECT "orders".* FROM "orders"
             WHERE "orders"."user_id" = 1 AND 
                   "orders"."state" IN ('pending', 'packed', 'shipped', 'in_transit', 'delivered', 'return_pending', 'returned')
      QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on orders  (cost=4.60..154.88 rows=40 width=3323)
   Recheck Cond: (user_id = 1)
   Filter: ((state)::text = ANY ('{pending,packed,shipped,in_transit,delivered,return_pending,returned}'::text[]))
   ->  Bitmap Index Scan on index_orders_on_user_id  (cost=0.00..4.59 rows=44 width=0)
         Index Cond: (user_id = 1)

因为我在user_idstate上搜索,并且这两个字段都有一个复合索引,为什么它不使用index_orders_on_user_id_and_state索引?或者我只是读这个解释输出错了?

这是两次通过吗?一个用user_id查找订单,然后另一个用于检查state

我需要在很多记录上同时运行这样的查询。因此,任何保持快速的方法都是非常好的。

2 个答案:

答案 0 :(得分:1)

数据库系统可能决定不使用索引。例如,使用Mysql,如果表数据很小,它可能决定进行全表扫描。您可以尝试输入数百万条记录并再次执行查询以查看计划的更改方式。

答案 1 :(得分:0)

对postgres索引的内部用法的一个很好的解释是:

https://devcenter.heroku.com/articles/postgresql-indexes

相关部分是

  

Postgres规划师可能选择不使用的原因有很多   一个索引。大多数情况下,规划者选择正确,即使它   不明白为什么。如果相同的查询使用索引扫描,也没关系   有些场合但不是其他场合。从中检索的行数   表可能会根据查询的特定常量值而有所不同   检索。因此,例如,查询计划程序可能是正确的   使用查询的索引select * from foo where bar = 1,然而   不要使用一个查询select * from foo where bar = 2,如果有的话   碰巧是更多的行,“bar”值为2.当这个   实际上,顺序扫描实际上可能比一个快得多   索引扫描,所以查询规划器实际上已经正确判断了   以这种方式执行查询的成本较低。