我有一个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)
为什么不使用索引?有关加快查询速度的提示吗?
答案 0 :(得分:0)
索引可能不够有选择性,因此Postgres决定需要读取整个表。对于您的查询,我建议在messages(created_at, user_id)
上建立一个索引。我们鼓励Postgres使用索引而不是原始数据,因为它是覆盖索引。
另一个想法是使created_at
(或created_at, user_id
)成为聚簇索引。这可能不会影响插入性能,因为新记录的created_at
值会更高,无论如何都要到最后。这会减少I / O.