理論から学ぶデータベース実践入門 ch13 リファクタリングの最適解
まとめ
リファクタリング
- DBリファクタリング: 1つ以上のテーブルの設計を変更する
- 定義変更自体はALTERコマンド一撃
- 現実、そんなに簡単な話ではない
- アプリケーションはリリース済、運用中
- テーブルにデータ格納済
- テーブルアクセス依存の処理がある
- アプリケーションはリリース済、運用中
DBのリファクタリングは大変
- 影響範囲甚大
- クエリの書き換え
- 各種制約の確認
- ビューの修正
- トリガーの修正
- ストアドプロシージャの修正
マルチアプリケーションにおけるDB環境
- 共通のDBを複数のアプリケーションから参照するのはよくあること
なぜリファクタリングが必要なのか
- アプリケーションが変化する以上、本質的に必要
- しかし大変なので「やらない理由」を探して放置しがち
- 負債は貯まるばかり
- 負債を返済するにはリファクタリングするほかない
リファクタリングの手順
- アプリケーションへの影響を抑えつつ、アプリケーションのペースに合わせた移行をするための手順
スキーマの移行期間
反復的なリファクタリング
回帰テスト
- 十分なテストケースが存在していることが前提
- アプリケーションの機能が損われたらリファクタリングではない、破壊しているだけ
- 機能が損われていないことを確認する方法はテストしかない
ベンチマークテスト
- リファクタリングの結果、パフォーマンスが著しく低下するケースは珍しくない
- パフォーマンスが低下していないことを確認する方法はベンチマークテストしかない
- 本番に忠実な環境を用意すること
- H/W
- パブリッククラウドのおかげで敷居下がった
- OS
- テストデータの規模
- H/W
マイグレーション利用のススメ
- スキーマのバージョン管理
- RoRのActive Recordで導入されたしくみ
- 【補】Laravelでもおなじみ
- 制限: バージョン分岐ができない
- 戻す場合のロジックもテストすること
- バックアップじゃダメなの?
- ダメ
- データも巻き戻ってしまう
トリガーを使って2つのテーブル間で同期を取る
- 移行期間中、新旧テーブルのデータの整合性を確保するために使う
- 循環に注意
- 移行が完了したらトリガーを削除する
- トリガーのテストも忘れずに
リファクタリングの種類
- よりよいDB設計とは
- どのようなリファクタリングで改善できるのか
インデックスの追加・削除
- 軽微
- クエリ書き換え生じない
- テーブルが持つ論理的な意味が変更されうることに注意
- 主キーやユニークインデックスによる一意性制約の導入/削除
- ベンチマークテストで性能劣化のなきことを確認せよ
カラム名の変更
- 過渡
- 異なる名前で同じデータを持ったカラムを2つ持たせる
- 行単位のトリガーで同期
- MySQLなどの製品でサポート
NOT NULL制約の導入
- 1NFにするために後からでもNOT NULLをつけることは大切
- あるいはリレーション分割
- NOT NULLをつけるにあたり、既存のデータにNULLが含まれていたら若干の調整が必要
- NULLだった個所の値がデフォルト値でもNULLでも動くようにクエリを書き換える
主キーの定義変更
無損失分解
- 移行期間が必要な場合は面倒
- 元のテーブルを残しつつ新しいテーブルを作成
- 双方のテーブルでデータの同期
- トリガー
- カスケード
テーブルの垂直分割と統合
- 複数のテーブルで直交性が満たされていない場合、テーブルの統合が必要
- 【補】 マスタの名寄せ的な
コラム: 関連テーブルの実態
- 1:N -> M:N
- 2段階のリファクタリングのショートカットと考えられる
- 主キーを変更して行持ち
- 第2正規化
リファクタリングのためのベストプラクティス
正規化と直交性
カラムではなくテーブルを追加する
- カラムを追加する前に熟考せよ:
- カラムの初期値はあるか
- 主キーに対して関数従属しているか
- これらを満たすならカラムを追加して問題ない
- テーブルを追加するというアプローチも
- メリット
- 既存のテーブルを変更しなくてよい
- デメリット
- JOIN増える
- 内部表に対して主キーでアクセスできる実行計画ならば、パフォーマンスペナルティは存外小さい
- JOIN増える
- メリット
SELECT * を使わない
- 1NF崩れる
- 順序を持ち込むことにほかならないため