# 当主题包含许多回复且用户已将其加入书签时，主题加载缓慢或根本不加载

**URL:** <https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201>\
**Category:** Bug\
**Created:** [2020年十月4日 15:26 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201 "2020-10-04T15:26:50Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![meriksson](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/meriksson/32/66712_2.png) [@meriksson](https://meta.discourse.org/u/meriksson)\
**Post date:** [2020年十月4日 15:26 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/1 "2020-10-04T15:26:50Z")

</div>

我们的 Discourse 论坛长期存在一个反复出现的问题，我们最终成功定位并能够可靠地复现该问题。

复现步骤如下：

1. 准备一个包含数千条回复的主题

2. 在该主题中书签某条帖子

3. 打开该主题

此时，该主题加载时间会显著变长。在某些情况下，加载会超时，并返回 Nginx 错误（502 Bad Gateway）。

以下是我们论坛中的一些大致加载时间数据：

- 对于约有 1,000 条回复的主题，创建书签后额外增加的加载时间为几秒。虽然可察觉，但并非严重问题。

- 对于约有 4,000 条回复的主题，加载时间通常为 20–30 秒，有时甚至超时，导致页面无法正常加载。

- 对于超过 9,000 条回复的主题，大多数情况下会超时。偶尔能够加载，但往往需要 30 秒以上。

请注意，如果这些主题中没有书签，它们可以正常加载。该问题仅出现在对特定主题拥有书签的用户身上；一旦他们移除书签，主题即可恢复正常加载。

---

<div class="post-metadata">

**Author:** ![Canapin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/canapin/32/119591_2.png) [@Canapin](https://meta.discourse.org/u/Canapin)\
**Post date:** [2020年十月4日 15:57 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/2 "2020-10-04T15:57:01Z")

</div>

我在论坛上有 30000 和 10000 条回复的主题中无法复现您的问题。🤷‍♂️

---

<div class="post-metadata">

**Author:** ![Lovgren](https://avatars.discourse-cdn.com/v4/letter/l/a3d4f5/32.png) [@Lovgren](https://meta.discourse.org/u/Lovgren)\
**Post date:** [2020年十月4日 17:56 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/3 "2020-10-04T17:56:13Z")

</div>

如果不太麻烦的话，能否您在复现步骤第2步设置书签时，尝试设置一个定时提醒，看看是否会有变化？正是这个方法最终让我成功复现了问题（具体而言，在我的情况下是设置了“周一”的提醒）。

这导致与书签帖子 ID 相关的 `.json-request` 在尝试 30 秒后开始返回 302 状态码，如下图所示。（在我点击个人资料菜单中的书签链接时出现。）

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

巧合的是，我还注意到搜索查询也开始表现出类似的行为，尽管只是变得极其缓慢，而且是在任何子论坛中搜索任何内容时都会发生，包括那些根本没有书签帖子的子论坛：

_[已编辑：来自 Chromium 开发者工具的慢速搜索查询截图，因仅允许一个嵌入]_

根据其他经验，这听起来像是某种 SQL N+1 问题，但我对 Discourse 代码和 Ruby 本身都还不够精通，无法确定是否可能是循环 JSON 模型或类似情况导致了同样的表现。

---

<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年十月4日 23:14 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/4 "2020-10-04T23:14:09Z")

</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年十月5日 23:01 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/5 "2020-10-05T23:01:51Z")

</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日 04:32 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/8 "2020-10-26T04:32:25Z")

</div>

此问题已在以下提交中修复：

> <https://github.com/discourse/discourse/commit/57d06518d419ad067a01ff1dc6836a44d5b4b685>
>
> 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.

cc @Macaw，他创建了相关话题 [Bookmarking a Post on a Large Topic creates Absurd Loading Times](https://meta.discourse.org/t/bookmarking-a-post-on-a-large-thread-creates-absurd-loading-times/168041)

---

<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年十月27日 15:56 UTC](https://meta.discourse.org/t/topics-load-slow-or-not-at-all-when-they-have-many-replies-and-user-has-bookmark-in-them/166201/9 "2020-10-27T15:56:44Z")

</div>


