大規模データ修正の進め方

## 大規模データ修正の進め方

### この記事の対象者

- 保守担当でデータ修正を取り扱う人

### はじめに

保守作業の一環で大規模なデータ修正を行うことがあります。
マスタを数レコード修正するような場合であればちょっとした非定例作業で終わりかもしれませんが、複数テーブルの数千万レコードを複雑な条件で修正したりするような場合はそういうわけにはいかず、一つのプロジェクトになったりすることもあります。
AP改修と共通するところも多くありますが、データ修正ならではというところもあります。
確立された方法論があるというわけでもないので、ここでは自分がやっている流れを紹介します。といっても基本的にはウォーターフォールです。

### 要件定義
まずは要件や計画を明確化してクライアントから承認を得る必要があります。
データ移行の場合は要件定義ではなくデータ移行計画ということもあります。
- システム停止について
ユーザの作業と重なった時にデータの状態が不整合になったり負荷がかかって障害が発生したりする可能性があるので、データ修正の作業時間中システム停止が必要になる場合があります。
これについてクライアントと合意を形成します。
 INSERT文だけでユーザが触る可能性がないとか、ユーザが操作した対象のデータはスキップして後日個別対応してよいなど、停止が不要なケースもあります。
 ユーザ操作と重ならないように処理対象のレコードを処理前にSELECT ～ FOR UPDATEでロックしたとしても十分ではありません。例えばユーザが画面を表示した直後（ユーザ側のSQLの処理は終了している）にデータ修正でDBの更新処理が走った場合、画面に表示されているデータとDBのデータが異なることで不具合が発生したりユーザの操作の判断に影響が出たりする可能性があるのでご注意ください。
 他のユーザが共有のデータを更新することはAP上で想定されているので何らかのチェック処理がある可能性が高いと思いますが、画面上で操作できないマスタデータなどを更新することは想定されていない可能性が高いと思われます。
 停止の日にちと時間、対象のシステムについて決めておいた方がいいですが、時間についてはこの段階では見積りが難しい場合もあるので必ずしもここで記載する必要はないと思います。
 
- バックアップ・リカバリ計画
何かあった時のための切り戻しをどうするか決めておきます。
データベースに関してはエクスポート・インポートかロールバックが普通だと思います。
システム停止を伴わない場合はユーザに影響が出ないようにロールバックになりますが、UNDO領域が足りないとか処理の途中でDDLがあるとかダイレクトパスインサートがあるとかSQLを一度終了して別の処理をしなければならないなどの理由で途中でコミットしなければならない場合があります。
このような場合は別途元に戻すSQLが必要になります。
事前にバックアップ用のテーブルにデータを退避しておいてDELETE（TRUNCATE）+INESRTするという手もありますが、外部キー制約や参照パーティションがあると難しくなってくるのでご注意ください。
システム停止時間についてはリカバリの時間も計算に入れます。

- スケジュール
本番環境の適用日をエンドとして逆算してスケジュールを引きます。
何の作業を誰がいつからいつまでにやるのか決めておきます。
特にクライアントのレビュー期間について合意を形成します。

- 対応内容
データ修正の内容についてクライアントの要望を抜け漏れなく記載します。
まだ詳細が完全に確定していない場合、可能であれば対応範囲や確定時期を決めて「ここまでに確定した内容しかやらない」とした方がいいでしょう。
要望に上がっていなくても必要な対応がある場合はここに記載します。
以降の工程で脈略なく作業が発生すると、クライアントが承認していない作業を勝手に実施することになってしまいます。
ただしあくまでもクライアント向けの資料なので、システム寄りの詳細レベルではなく業務よりの概要レベルにとどめます。

- 成果物
成果物一覧について記載します。

### 基本設計
通常、保守作業でのAP改修の場合は既存の基本設計書に手を加えることになりますが、データ修正においては大抵そういうわけではありません。（データベース定義の修正を含む場合は論理ER図などの修正が必要になる場合はあります）
考え方としては、要件定義の対応内容を満たすために必要なシステム上の対応を記載する、その作業限りの設計書という形になります。
規模感にもよるので絶対に必要というわけではありません。
- メリット
この作業は現場のルール上でも存在しないかもしれませんが、内容が複雑であったりクライアントの要望がシステムから見て曖昧な場合は自主的に実施した方がいいでしょう。
設計を飛ばしていきなりSQLなどを書くこともできますが、SQLのどの部分が要件定義書のどの部分に対応していて、その処理で本当に問題ないのかわかりにくくなります。自分ではわかっていても他の人から見ると論理の飛躍があったりするため、推測や憶測を交えながらレビューやチェックをすることになり、結果として不具合が残る場合があります。
- 内容
データベースのどのテーブルのどのレコードをどういう条件で修正するか、ファイルをどこからどこに移動するかといった内容になります。
要件定義書の対応内容を抜粋して対応付けて記載した方がいいです。抜け漏れを防ぐことができ、インプットとアウトプットの関係が明確になります。

### 詳細設計
データ修正ではSQLやバッチ、シェルスクリプトなどを使用することが多いと思います。
ここではまとめてスクリプトと呼びます。
ここでの設計はスクリプトの設計なので詳細設計ではなくスクリプト設計と言ってもいいです。
基本設計書の内容と対応付けて、スクリプトの構造や意図を記載します。
あまりきっちり書きすぎるとスクリプトを見た方が早いということになってしまうので形式ばらない方がいいです。場合によってはメモ書きでも十分だと思います。

### 製造
詳細設計を元にスクリプトを書きます。
保守の観点からはできるだけコメントを書いていただけると後々見返した時に楽になります。

### 単体テスト
基本設計書および詳細設計書の対応内容が実現できていることをテスト項目にします。
主に検証用SQLを用意して全データが正しく処理できていることを確認します。
単体テストの観点については過去の以下の記事を参考にしてみてください。
https://qiita.com/cross_hino/items/87821842111456b89ab9
なおSQLだけで完結することが多いので結合テストに相当するものは通常必要ありませんが、例えばレコードにファイルパスを記載していてSQLの実行後にファイルの移動を行うようなスクリプトの場合は別途用意した方がよいかもしれません。

### 総合テスト
要件定義書の対応内容が実現できていることをテスト項目にします。
クライアントにもレビューしてもらうので、テスト項目の確認方法は画面確認がメインです。
全量確認は大抵難しいのでサンプル確認になります。

### リハーサル
作業手順書を作成して本番相当の環境でリハーサルを実施します。
戻しの手順も確認した方がいいですが、エクスポート・インポートなど他の作業と共通で確認済の内容なら毎回確認しなくてもよいという判断になるかもしれません。
### 本番作業
現場のルールに則って粛々と作業を進めます。