ここではバッジのバックフィル処理を見ています:
特に、以下のクエリに問題があるようです(Long-Running Sidekiq Jobs を参照)。
sql = <<~SQL
DELETE FROM user_badges
WHERE id IN (
SELECT ub.id
FROM user_badges ub
LEFT JOIN (
#{badge.query}
) q ON q.user_id = ub.user_id
#{post_clause}
WHERE ub.badge_id = :id AND q.user_id IS NULL
)
SQL
このクエリは LEFT JOIN を使用しているため、一致の有無に関わらず user_badges のすべての結果が返されます。しかし、この部分が非常に混乱を招きます:
ON q.user_id = ub.user_id
...
AND q.user_id IS NULL
このクエリは user_id が一致する行で結合を行いますが、その後 WHERE 句でそれらの行を破棄してしまいます。そのため、その結合は実質的に無意味になっています。そこで疑問に思う点は以下の通りです:
-
バックフィル関数の目的は何ですか?処理中のバッジを完全に削除し、一度に再構築しているように見えます。これは必要でしょうか?
-
この関数において、投稿を対象とするバッジとそうでないバッジの違いは何ですか?LEFT JOIN を使用している場合、再構築のために削除する正しい badge_id を特定する際に、これは本当に重要でしょうか?