【发布时间】:2021-11-09 03:54:52
【问题描述】:
我有一个模型 Activity,它有很多 ActivitySecondaryUser。我正在尝试优化此查询:
2.6.3 :015 > Activity.left_joins(:activity_secondary_users).where("activity_secondary_users.user_id = :id OR (primary_user_id = :id AND activity_type != '#{Activity::MENTION}')", id: 10000).order(created_at: :desc).limit(10).explain
Activity Load (812.7ms) SELECT "activities".* FROM "activities" LEFT OUTER JOIN "activity_secondary_users" ON "activity_secondary_users"."activity_id" = "activities"."id" WHERE (activity_secondary_users.user_id = 10000 OR (primary_user_id = 10000 AND activity_type != 'mention')) ORDER BY "activities"."created_at" DESC LIMIT $1 [["LIMIT", 10]]
=> EXPLAIN for: SELECT "activities".* FROM "activities" LEFT OUTER JOIN "activity_secondary_users" ON "activity_secondary_users"."activity_id" = "activities"."id" WHERE (activity_secondary_users.user_id = 10000 OR (primary_user_id = 10000 AND activity_type != 'mention')) ORDER BY "activities"."created_at" DESC LIMIT $1 [["LIMIT", 10]]
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=1000.87..19659.54 rows=10 width=138) (actual time=79.769..737.253 rows=10 loops=1)
Buffers: shared hit=2013672
-> Gather Merge (cost=1000.87..202514.52 rows=108 width=138) (actual time=79.768..737.245 rows=10 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=2013672
-> Nested Loop Left Join (cost=0.84..201502.03 rows=45 width=138) (actual time=36.208..351.256 rows=5 loops=3)
Filter: ((activity_secondary_users.user_id = 10000) OR ((activities.primary_user_id = 10000) AND ((activities.activity_type)::text <> 'mention'::text)))
Rows Removed by Filter: 181610
Buffers: shared hit=2013672
-> Parallel Index Scan using index_activities_on_created_at on activities (cost=0.42..28991.70 rows=370715 width=138) (actual time=0.027..52.295 rows=181615 loops=3)
Buffers: shared hit=137766
-> Index Scan using index_activity_secondary_users_on_activity_id on activity_secondary_users (cost=0.42..0.45 rows=1 width=16) (actual time=0.001..0.001 rows=0 loops=544845)
Index Cond: (activity_id = activities.id)
Buffers: shared hit=1875906
Planning Time: 0.216 ms
Execution Time: 737.288 ms
索引:
- 活动:created_at、primary_user_id
- ActivitySecondaryUser:activity_id
我已尝试添加其他索引并更改排序属性,但似乎没有什么能让它更快。该表的记录少于 100 万条,平均耗时超过 500 毫秒。有关如何优化查询的任何建议?
【问题讨论】:
-
当您多次运行每个查询时,您是否看到相同的差异?我相信第一次运行查询时可能会有一些开销,因为查询计划是制定然后缓存的。
-
@LesNightingill asc 查询的整体性能确实更好。我确实发现,对于更高的 id,asc 和 desc 的查询都非常慢(有时超过 400 毫秒)
-
请显示
EXPLAIN (ANALYZE, BUFFERS),而不仅仅是解释。 -
@jjanes 添加到问题
标签: ruby-on-rails postgresql optimization activerecord rails-activerecord