# 在大型主题上收藏帖子会导致加载时间过长

**URL:** <https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041>\
**Category:** Bug\
**Created:** [2020年十月23日 05:01 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041 "2020-10-23T05:01:21Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Macaw](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/macaw/32/196285_2.png) [@Macaw](https://meta.discourse.org/u/Macaw)\
**Post date:** [2020年十月23日 05:01 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/1 "2020-10-23T05:01:21Z")

</div>

[这个](https://devforum.roblox.com/t/what-are-you-working-on-currently-2020/419774)帖子尤其让我困扰了很久。我曾问：为什么加载需要 1 到 3 分钟，甚至有时根本加载不出来？

在看到有人在 [这篇](https://devforum.roblox.com/t/edit-bookmarks-cause-large-threads-to-take-an-abnormally-long-time-to-load/832983) 帖子中再次提到该问题后，我决定深入调查：我从那个拥有 4,500 条回复的帖子中移除了所有书签。

结果它像其他普通帖子一样瞬间加载完成。

随后我思考：还有哪些方法可以验证这一点？

- 无论我是否将首帖或最新帖设为书签，加载时间仍然较长，虽然不是几分钟，但大约需要 10 秒。
- 帖子数量越多，该现象越明显；我感觉在约 4000 条回复左右存在某个阈值，会导致加载时间变得如此缓慢。
- 我在其他超过 4000 条回复的帖子中也进行了测试。
- 一个主题拥有的书签越多，加载时间就越长。

我的推测是：在一个帖子数量很多的话题中，书签数量越多，加载所需时间就越长。

* * *

复现步骤：打开一个包含大量回复的主题，并将其中一条帖子设为书签。遗憾的是，要书签帖子需要登录，而本网站上回复最多的帖子仅有 925 条回复。

如果需要我提供更多详细信息，请随时提出。

---

<div class="post-metadata">

**Author:** ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)\
**Post date:** [2020年十月23日 05:55 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/2 "2020-10-23T05:55:20Z")

</div>

我之前好像在另一个话题里向 @martin 报告过这个问题。

---

<div class="post-metadata">

**Author:** ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)\
**Post date:** [2020年十月25日 23:17 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/3 "2020-10-25T23:17:10Z")

</div>

嗯，是的，你确实提到了这个：[https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201。抱歉，我好像疏忽了这一点；我会把这个问题移到我的待办事项列表的最前面。](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201%E3%80%82%E6%8A%B1%E6%AD%89%EF%BC%8C%E6%88%91%E5%A5%BD%E5%83%8F%E7%96%8F%E5%BF%BD%E4%BA%86%E8%BF%99%E4%B8%80%E7%82%B9%EF%BC%9B%E6%88%91%E4%BC%9A%E6%8A%8A%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%E7%A7%BB%E5%88%B0%E6%88%91%E7%9A%84%E5%BE%85%E5%8A%9E%E4%BA%8B%E9%A1%B9%E5%88%97%E8%A1%A8%E7%9A%84%E6%9C%80%E5%89%8D%E9%9D%A2%E3%80%82)

---

<div class="post-metadata">

**Author:** ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)\
**Post date:** [2020年十月26日 00:17 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/4 "2020-10-26T00:17:11Z")

</div>

如果稳定版中存在此问题，其严重性也足以支持将其向后移植。

---

<div class="post-metadata">

**Author:** ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)\
**Post date:** [2020年十月26日 01:22 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/5 "2020-10-26T01:22:26Z")

</div>

我在 Roblox 论坛上创建了一个账号，查看了 [https://devforum.roblox.com/t/what-are-you-working-on-currently-2020/419774/5043，并在那里复现了该问题。没有书签时，主题加载时间约为](https://devforum.roblox.com/t/what-are-you-working-on-currently-2020/419774/5043%EF%BC%8C%E5%B9%B6%E5%9C%A8%E9%82%A3%E9%87%8C%E5%A4%8D%E7%8E%B0%E4%BA%86%E8%AF%A5%E9%97%AE%E9%A2%98%E3%80%82%E6%B2%A1%E6%9C%89%E4%B9%A6%E7%AD%BE%E6%97%B6%EF%BC%8C%E4%B8%BB%E9%A2%98%E5%8A%A0%E8%BD%BD%E6%97%B6%E9%97%B4%E7%BA%A6%E4%B8%BA) 1.3 秒；而有书签时则需约 8 秒。我甚至遇到了 502 网关错误：

 ![image](https://global.discourse-cdn.com/meta/original/3X/b/5/b554be3bdbeb1e563d8660dfcaecef122488f64f.png)

不过，我在本地创建了一个包含 5000 条帖子的主题并添加了书签，结果发现无论该主题中是否有书签，加载时间都相同：🤷‍♂️。我需要继续排查……加载用户主题中标签的代码位于：

> <https://github.com/discourse/discourse/blob/9aa2723d57cf9edaad0873ba64d3d1e5a9d7fdc7/lib/topic_view.rb#L443-L445>

而为每条帖子查找书签的代码位于：

> <https://github.com/discourse/discourse/blob/9aa2723d57cf9edaad0873ba64d3d1e5a9d7fdc7/app/serializers/post_serializer.rb#L361-L364>

在我看来，这段代码并不显得异常或性能消耗大。`user_post_bookmarks` 只会查询一次数据库，因为它被缓存了，所以这里不存在 N+1 查询问题。此外，以下是用于检查主题级别是否存在书签的主题视图代码：

> <https://github.com/discourse/discourse/blob/9aa2723d57cf9edaad0873ba64d3d1e5a9d7fdc7/app/serializers/topic_view_serializer.rb#L190-L200>

> <https://github.com/discourse/discourse/blob/9aa2723d57cf9edaad0873ba64d3d1e5a9d7fdc7/lib/topic_view.rb#L346-L354>

这里也没有发现任何可疑之处……

---

<div class="post-metadata">

**Author:** ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)\
**Post date:** [2020年十月26日 01:26 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/6 "2020-10-26T01:26:06Z")

</div>

这会不会是我们之前在旧版本中已经修复的 bug？🤔

---

<div class="post-metadata">

**Author:** ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)\
**Post date:** [2020年十月26日 01:37 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/7 "2020-10-26T01:37:38Z")

</div>

我不这么认为，Roblox 论坛使用的是版本 [https://github.com/discourse/discourse/commit/2a268bd89b4eebe4941b98030db9d920ee98d406。自那以后，只有两个与书签相关的提交是我做的，它们都没有涉及主题书签的加载或序列化。](https://github.com/discourse/discourse/commit/2a268bd89b4eebe4941b98030db9d920ee98d406%E3%80%82%E8%87%AA%E9%82%A3%E4%BB%A5%E5%90%8E%EF%BC%8C%E5%8F%AA%E6%9C%89%E4%B8%A4%E4%B8%AA%E4%B8%8E%E4%B9%A6%E7%AD%BE%E7%9B%B8%E5%85%B3%E7%9A%84%E6%8F%90%E4%BA%A4%E6%98%AF%E6%88%91%E5%81%9A%E7%9A%84%EF%BC%8C%E5%AE%83%E4%BB%AC%E9%83%BD%E6%B2%A1%E6%9C%89%E6%B6%89%E5%8F%8A%E4%B8%BB%E9%A2%98%E4%B9%A6%E7%AD%BE%E7%9A%84%E5%8A%A0%E8%BD%BD%E6%88%96%E5%BA%8F%E5%88%97%E5%8C%96%E3%80%82)

> <https://github.com/discourse/discourse/commit/0d63eb412404330b943f367c4cdbc2021b900995>
>
> This PR introduces a feature that will detect a date inside the post that a user… is bookmarking, and offer that date as an option in the bookmark modal.
> 
> The logic is that we get the first date/time detected in the post. If it does not have a time, just a date, then we default to 8:00am for the time.

> <https://github.com/discourse/discourse/commit/c3cede697dddeacabc6410ff4e4f8425805004cb>
>
> When posts or topics are deleted we don't want to immediately delete associated …bookmarks, so we have a grace period to recover them and their reminders if the post or topic is un-deleted. This PR adds a task to the Weekly scheduled job to go and delete bookmarks attached to posts or topics deleted \> 3 days ago.

我想一定是有什么其他奇怪的巧合在起作用？

---

<div class="post-metadata">

**Author:** ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)\
**Post date:** [2020年十月26日 02:25 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/8 "2020-10-26T02:25:38Z")

</div>

我可以在 BBS 上复现此问题。

 ![image](https://global.discourse-cdn.com/meta/original/3X/f/9/f9786773440b6bf4ebcd85a4920853f15b1bcef5.png)

> **[Ongoing coronavirus happenings](https://bbs.boingboing.net/t/ongoing-coronavirus-happenings/160918?pp=enable)**
>
> Figured having a single spot to drop info might decrease clutter. We shall see.

该查询似乎存在问题，导致查询规划器出错。请查看执行计划并进行一些调整。

我猜测，只需进行一些非常微小的改动，就能将执行时间从近 4 秒降低到 1 毫秒。

提醒各位读者：启用 MiniProfiler 至关重要，它能帮助你定位有问题的查询。

---

<div class="post-metadata">

**Author:** ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)\
**Post date:** [2020年十月26日 02:52 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/9 "2020-10-26T02:52:18Z")

</div>

感谢 @sam 的建议，我发现问题出在以下这行代码执行的查询计划不佳：

```plaintext
topic.posts.with_deleted.where(post_number: 1).first

```

生成的 SQL 包含 `LIMIT 1`，导致 `index_posts_on_topic_id_and_post_number` 索引未被使用，从而造成巨大延迟。我在本地无法复现此问题，因为本地数据库中几乎没有帖子；基本上，整个 Discourse 论坛中的帖子越多，此问题就越严重。我很快就会提供修复方案。

---

<div class="post-metadata">

**Author:** ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)\
**Post date:** [2020年十月26日 03:39 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/10 "2020-10-26T03:39:44Z")

</div>

此问题已作为重复项关闭，参见：

> [@Topics load slow or not at all when they have many replies and user has bookmark in them](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201):
>
> We have had a recurring problem on our Discourse forum for a while and we finally managed to narrow it down and reliably recreate it. Here are the steps to recreate: Have a topic with thousands of replies Bookmark a post in that topic Open the topic The topic now takes a long time to load. In some cases it times out and we get an Ngnix error instead (502 Bad Gateway). Here are some approximate loading times from our forum: For a topic with about 1,000 replies, the extra loading …

@martin，问题解决后，你可以在原主题下继续发帖。

---

<div class="post-metadata">

**Author:** ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)\
**Post date:** [2020年十月26日 03:39 UTC](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-topic-creates-absurd-loading-times/168041/11 "2020-10-26T03:39:47Z")

</div>


