From b3920e05e73fd383dd56fac5d44ab659987f7e55 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 23 Nov 2023 18:15:40 +1100 Subject: [PATCH] PERF: avoid table scan while performing a very large update (#24525) We were seeing lots of deadlocks deploying this migration. This improves the situation in 2 ways. 1. ddl transaction is avoided, so we hold locks for far shorter times 2. we operate in chunks of a maximum of 100_000 posts (though it is heavily filtered down) * improve code so it is clearer --- ...igger_post_rebake_category_style_quotes.rb | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/db/post_migrate/20231120190818_trigger_post_rebake_category_style_quotes.rb b/db/post_migrate/20231120190818_trigger_post_rebake_category_style_quotes.rb index 7adb3ed7e9f..ea3837f529e 100644 --- a/db/post_migrate/20231120190818_trigger_post_rebake_category_style_quotes.rb +++ b/db/post_migrate/20231120190818_trigger_post_rebake_category_style_quotes.rb @@ -1,12 +1,31 @@ # frozen_string_literal: true class TriggerPostRebakeCategoryStyleQuotes < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + def up - DB.exec(<<~SQL) - UPDATE posts - SET baked_version = NULL - WHERE cooked LIKE '%blockquote%' + max_id = DB.query_single(<<~SQL).first.to_i + SELECT MAX(id) + FROM posts SQL + + chunk_size = 100_000 + while max_id > 0 + ids = DB.query_single(<<~SQL, start: max_id - chunk_size, finish: max_id) + SELECT id + FROM posts + WHERE cooked LIKE '%blockquote%' + AND id >= :start AND id <= :finish + SQL + + DB.exec(<<~SQL, ids: ids) if ids && ids.length > 0 + UPDATE posts + SET baked_version = NULL + WHERE id IN (:ids) + SQL + + max_id -= chunk_size + end end def down