# 长时间运行的 Sidekiq 任务

**URL:** <https://meta.discourse.org/t/long-running-sidekiq-jobs/173974>\
**Category:** Feature\
**Created:** [2020年十二月22日 02:45 UTC](https://meta.discourse.org/t/long-running-sidekiq-jobs/173974 "2020-12-22T02:45:20Z")\
**Posts on this page:** 2\
**Page:** 2

<div class="post-metadata">

**Author:** ![Ghan](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ghan/32/177964_2.png) [@Ghan](https://meta.discourse.org/u/Ghan)\
**Post date:** [2020年十二月24日 04:19 UTC](https://meta.discourse.org/t/long-running-sidekiq-jobs/173974/21 "2020-12-24T04:19:16Z")

</div>

> [@sam](#):
>
> 排名是按主题进行的，并不是对整个集合进行排名。

无论实际要更新多少个排名，它仍然必须运行子查询来计算整个 posts 表中每个主题的排名。

这个子查询大约需要 40 秒才能运行，而且它位于一个嵌套循环内部，该循环必须在进入 WHERE 子句之前为连接操作执行。这似乎就是导致查询成本激增的原因。

```sql
SELECT id, percent_rank() \n OVER (PARTITION BY topic_id ORDER BY SCORE DESC) as percent_rank \nFROM posts

```

---

<div class="post-metadata">

**Author:** ![Ghan](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ghan/32/177964_2.png) [@Ghan](https://meta.discourse.org/u/Ghan)\
**Post date:** [2020年十二月24日 17:16 UTC](https://meta.discourse.org/t/long-running-sidekiq-jobs/173974/22 "2020-12-24T17:16:08Z")

</div>

> [@sam](#):
>
> 可能在初始更新完成后，运行速度会更快。

我查看了代码，现在明白了。这个查询会反复执行，直到清除所有需要更新排名的帖子。因此，当我观察 SQL 进程时，在数小时内看到该查询多次运行，每完成一次运行后紧接着开始下一次。

不过，LIMIT 似乎并没有显著降低查询的复杂度。事实上，我发现如果将 LIMIT 增加到 200000，查询计划反而会有显著改善。  
当 LIMIT 为 20000 时，我看到的嵌套循环成本接近 2 亿：

`-> Nested Loop (cost=6033694.44..190270554.32 rows=26680560 width=16)`

如果我将 LIMIT 直接增加到 200000，生成的查询计划看起来就干净多了：

```plaintext
                                                            QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
 Update on posts (cost=7334394.89..8873863.82 rows=200000 width=833)
   -> Nested Loop (cost=7334394.89..8873863.82 rows=200000 width=833)
         -> Subquery Scan on x (cost=7334394.45..7370147.82 rows=200000 width=48)
               -> Limit (cost=7334394.45..7368147.82 rows=200000 width=12)
                     -> Hash Join (cost=7334394.45..11837188.36 rows=26680560 width=12)
                           Hash Cond: (posts_1.id = y.id)
                           Join Filter: ((posts_1.percent_rank IS NULL) OR (y.percent_rank <> posts_1.percent_rank))
                           -> Hash Join (cost=35403.20..2845221.73 rows=26703700 width=12)
                                 Hash Cond: (posts_1.topic_id = topics.id)
                                 -> Seq Scan on posts posts_1 (cost=0.00..2739721.00 rows=26703700 width=16)
                                 -> Hash (cost=23918.11..23918.11 rows=918807 width=4)
                                       -> Index Only Scan using topics_pkey on topics (cost=0.42..23918.11 rows=918807 width=4)
                           -> Hash (cost=6834805.00..6834805.00 rows=26703700 width=12)
                                 -> Subquery Scan on y (cost=6033694.00..6834805.00 rows=26703700 width=12)
                                       -> WindowAgg (cost=6033694.00..6567768.00 rows=26703700 width=24)
                                             -> Sort (cost=6033694.00..6100453.25 rows=26703700 width=16)
                                                   Sort Key: posts_2.topic_id, posts_2.score DESC
                                                   -> Seq Scan on posts posts_2 (cost=0.00..2739721.00 rows=26703700 width=16)
         -> Index Scan using posts_pkey on posts (cost=0.44..7.52 rows=1 width=789)
               Index Cond: (id = x.id)
 JIT:
   Functions: 30
   Options: Inlining true, Optimization true, Expressions true, Deforming true
(23 rows)

```

我不确定是什么导致了这种切换。在我们刚完成的大规模导入之后，至少暂时提高这个限制可能是值得的，以便尽快清理积压任务。

[上一頁](https://meta.discourse.org/t/long-running-sidekiq-jobs/173974.md?page=1)
