为什么这个查询运行缓慢?

3

我想知道为什么要执行

UserView.where(:user_viewable_type => 'Song').order('created_at desc').limit(5) 

需要运行1213毫秒。有点慢,不是吗?

在schema.rb中,user_viewable_type被索引了:

add_index "user_views", ["user_viewable_type"], :name => "index_views_on_viewable_type"

即使在psql中:

"index_views_on_viewable_type" btree (user_viewable_type)

使用.explain运行返回:

UserView.where(:user_viewable_type => 'Song').order('created_at desc').limit(5).explain
  UserView Load (1801.4ms)  SELECT "user_views".* FROM "user_views" WHERE "user_views"."user_viewable_type" = 'Song' ORDER BY created_at desc LIMIT 5
  EXPLAIN (1.6ms)  EXPLAIN SELECT "user_views".* FROM "user_views" WHERE "user_views"."user_viewable_type" = 'Song' ORDER BY created_at desc LIMIT 5
=> "EXPLAIN for: SELECT  \"user_views\".* FROM \"user_views\"  WHERE \"user_views\".\"user_viewable_type\" = 'Song' ORDER BY created_at desc LIMIT 5\n                                  QUERY PLAN\n-------------------------------------------------------------------------------\n Limit  (cost=17113.28..17113.28 rows=5 width=37)\n   ->  Sort  (cost=17113.28..17147.82 rows=69085 width=37)\n         Sort Key: created_at\n         ->  Seq Scan on user_views  (cost=0.00..16883.78 rows=69085 width=37)\n               Filter: ((user_viewable_type)::text = 'Song'::text)\n(5 rows)\n"

所以我决定拆分查询并删除order,我得到了:
UserView.where(:user_viewable_type => 'Song').limit(5).explain
UserView Load (1.6ms)  SELECT "user_views".* FROM "user_views" WHERE "user_views"."user_viewable_type" = 'Song' LIMIT 5

看起来order('created_at desc')导致了查询变慢。但是为什么?按顺序排序不应该很快吗?

我尝试在id列上使用order

UserView.where(:user_viewable_type => 'Song').order('id desc').limit(5).explain
UserView Load (44.8ms)  SELECT "user_views".* FROM "user_views" WHERE "user_views"."user_viewable_type" = 'Song' ORDER BY id desc LIMIT 5

速度快多了!可能出了什么问题?

我需要提到几件事:

  1. 如果你还没有注意到,这是一个多态表。
  2. 过去,我通过Rails迁移将:live_viewable_type重命名为:user_viewable_type,通过t.rename :live_viewable_type, :user_viewable_type。然而,我认为这不应该是问题,因为索引仍在正确的列上。

将您的问题中的“Explain”替换为“Explain analyze”,并使用换行符格式化为代码,以便阅读。 - Mike Sherrill 'Cat Recall'
1个回答

3
根据我的理解,这个问题可能是由以下两个原因之一导致的:
a) 你没有在created_at上建立索引。
或者
b) 数据库在选择索引时会使用created_at索引,使得user_viewable_type的查询变慢,或者反过来。
如果你经常进行这些调用,那么最好考虑在[created_at, user_viewable_type]上建立一个组合索引(或者另一种方式:[user_viewable_type, created_at]),这取决于哪种方式可以更快地缩小你的结果。

我刚读过一篇类似的文章,解释了你的建议:http://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes - Christian Fazzini
对,他写的基本上和我想的差不多。如果你在[created_at, user_viewable_type]上建立索引,结果会更好吗? - DRobinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接