mirror of
https://github.com/discourse/discourse.git
synced 2024-12-14 04:33:43 +08:00
FIX: Prevent slow bookmark first post reminder at query for topic (#11024)
On forums with a large amount of posts when a user had a bookmark in the topic, PostgreSQL was using an inefficient query plan to fetch the first post of the topic. When running this ActiveRecord query: ``` topic.posts.with_deleted.where(post_number: 1).first ``` The following query plan was produced: ``` Limit (cost=0.43..583.49 rows=1 width=891) (actual time=3850.515..3850.515 rows=1 loops=1) -> Index Scan using posts_pkey on posts (cost=0.43..391231.51 rows=671 width=891) (actual time=3850.514..3850.514 rows=1 loops=1) Filter: ((topic_id = 160918) AND (post_number = 1)) Rows Removed by Filter: 2274520 Planning time: 0.200 ms Execution time: 3850.559 ms (6 rows) ``` The issue here is the combination of ORDER BY and LIMIT causing the ineficcient Index Scan using posts_pkey on posts to be used. When we correct the AR call to this: ``` topic.posts.with_deleted.find_by(post_number: 1) ``` We end up with a query that still has a LIMIT but no ORDER BY, which in turn creates a much more efficient query plan: ``` Limit (cost=0.43..1.44 rows=1 width=891) (actual time=0.033..0.034 rows=1 loops=1) -> Index Scan using index_posts_on_topic_id_and_post_number on posts (cost=0.43..678.82 rows=671 width=891) (actua l time=0.033..0.033 rows=1 loops=1) Index Cond: ((topic_id = 160918) AND (post_number = 1)) Planning time: 0.167 ms Execution time: 0.072 ms (5 rows) ``` This query plan uses the correct index, `Index Scan using index_posts_on_topic_id_and_post_number on posts`. Note that this is only a problem on forums with a larger amount of posts; tiny forums would not notice the difference. On large forums a query for a topic that takes 1s without a bookmark can take 8-30 seconds, and even end up with 502 errors from nginx.
This commit is contained in:
parent
1829ca605e
commit
c7cefb8e08
|
@ -355,7 +355,12 @@ class TopicView
|
|||
end
|
||||
|
||||
def first_post_bookmark_reminder_at
|
||||
@topic.first_post.bookmarks.where(user: @user).pluck_first(:reminder_at)
|
||||
@first_post_bookmark_reminder_at ||= \
|
||||
begin
|
||||
first_post = @topic.posts.with_deleted.find_by(post_number: 1)
|
||||
return if !first_post
|
||||
first_post.bookmarks.where(user: @user).pluck_first(:reminder_at)
|
||||
end
|
||||
end
|
||||
|
||||
MAX_PARTICIPANTS = 24
|
||||
|
|
Loading…
Reference in New Issue
Block a user