缓慢的activerecord / postgres查询不使用索引

时间:2016-06-12 13:51:15

标签: ruby-on-rails postgresql activerecord

我有一个Messages表,其中user_id字段(字符串)。对总独特用户的查询非常缓慢,有超过一百万条记录。

Message.where(created_at: start_date..end_date).select(:user_id).distinct(:user_id).count
=> (120145.6ms)  SELECT DISTINCT COUNT(DISTINCT "messages"."user_id") FROM "messages" WHERE ("messages"."created_at" BETWEEN '2016-05-14 04:00:00.000000' AND '2016-06-13 03:59:59.999000')

我有user_id&的索引created_at,但postgres似乎没有使用它们:

模式

add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree
add_index "messages", ["created_at"], name: "index_messages_on_created_at", using: :btree   

PG解释

                                                                        QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=56111.04..56291.89 rows=18085 width=29)
   Group Key: user_id
   ->  Seq Scan on messages  (cost=0.00..52215.65 rows=1558153 width=29)
         Filter: ((created_at >= '2016-05-14 04:00:00'::timestamp without time zone) AND (created_at <= '2016-06-13 03:59:59.999'::timestamp without time zone))
(4 rows)

为什么不使用索引?有关加快查询速度的提示吗?

1 个答案:

答案 0 :(得分:0)

索引可能不够有选择性,因此Postgres决定需要读取整个表。对于您的查询,我建议在messages(created_at, user_id)上建立一个索引。我们鼓励Postgres使用索引而不是原始数据,因为它是覆盖索引。

另一个想法是使created_at(或created_at, user_id)成为聚簇索引。这可能不会影响插入性能,因为新记录的created_at值会更高,无论如何都要到最后。这会减少I / O.