はじめに

元々日次で実行していたバッチの実装に不備があり、本来 insert されて欲しいレコードが作成されずに宙ぶらりんになったレコードが作成されてしまっていた。 作成されてしまったレコード自体は不要になるわけではなかったので、バッチの修正と対象レコードのリカバリを行うことにした。

やったこと

以下を順に対応した。

  • バッチの修正
  • リカバリ対象の抽出
  • リカバリバッチの作成
  • 動作確認・実行

バッチの修正については今回書きたいトピックではないので割愛する。

リカバリ対象の抽出

まずはどの程度対象レコードがあるかを調べた。幸い本番のデータを日次でバックアップしているデータベースがあるのでそちらを利用した。 条件として、親子関係のテーブルで子のレコードが 1 件も作成されていないレコードが対象だった。 検索した結果、全件で 1000 万件以上はリカバリ対象の候補となった。

対象のテーブルはサービスから頻繁に参照されるので対象レコードの取得と insert は効率よく行う必要があった。 join を使ったレコード取得は非効率だったので、日毎に該当レコードの min id / max id を検索しておいて、id の範囲を使って対象レコードを抽出するようにした。 最終的に数ヶ月ごとの範囲でバッチは実行したので日毎での min / max を取得したのは冗長ではあった。

リカバリバッチの作成

リカバリ対象は洗い出せたので、id の範囲を渡してリカバリを行うようなバッチを作成した。 テーブル構造から重複したレコードが作成できないことは確認できていたので、子レコードを bulk insert する方式を採った。

今回は運よくテーブル定義に助けられたが、重複レコードが作成されてしまう構造でないかは予め確認しておいた方が良い。 index が貼られていて insert 済みのレコードが検索しやすければ良いが、そうでない場合はまた別の方法を考える必要があると思う。

動作確認・実行

検証用の環境があるので実行結果と実行時間を確認してから本番実行するようにした。 ここまでのデータリカバリは初ということもあったので一気にリカバリを実行するのではなく分割してリカバリを行った。 バッチ内での limit を使った一定件数ごとに取得した処理に加えて、実行対象の範囲を指定する組み合わせを採用した。

結果としては途中でエラーが出ることもなくバッチを実行しきることができた。

まとめ

今回は作成漏れのレコードを作成するという修正作業だったが、反対に削除をする作業だとより慎重に作業しないとだろうなと思う。

自分が対応し終わった後で 受取期限の過ぎたデータをMySQL上から削除する話 | GREE Engineering という記事を見つけて、選択した方針は悪くなかったなと感じた。

こういったデータの補填作業は地味だけど、データ量が多いと考えることも増えるし、ソシャゲだと必要な処理だろうし大変だなーと思った。