理論から学ぶデータベース実践入門 ch13 リファクタリングの最適解

RDBSQL勉強メモ

出典: 


まとめ

  • DBリファクタリングは必須

    • DB設計の問題は技術的負債
    • 負債は雪だるま式に増える
  • 計画的に

    • 移行期間を設けるなど

      • 整合性の確保にトリガーが大変役に立つ
  • 参考図書: データベース・リファクタリング

    • 守備範囲

      • どのようなリファクタリングがあるか
    • 守備範囲外

      • どのようなDB設計にすべきか
      • リファクタリングによってどのような改善を行うべきか

リファクタリング

  • DBリファクタリング: 1つ以上のテーブルの設計を変更する
  • 定義変更自体はALTERコマンド一撃
  • 現実、そんなに簡単な話ではない

    • アプリケーションはリリース済、運用中

      • テーブルにデータ格納済
      • テーブルアクセス依存の処理がある

DBのリファクタリングは大変

  • 影響範囲甚大

    • クエリの書き換え
    • 各種制約の確認
    • ビューの修正
    • トリガーの修正
    • ストアドプロシージャの修正

マルチアプリケーションにおけるDB環境

  • 共通のDBを複数のアプリケーションから参照するのはよくあること

なぜリファクタリングが必要なのか

  • アプリケーションが変化する以上、本質的に必要
  • しかし大変なので「やらない理由」を探して放置しがち

    • 負債は貯まるばかり
  • 負債を返済するにはリファクタリングするほかない

リファクタリングの手順

  • アプリケーションへの影響を抑えつつ、アプリケーションのペースに合わせた移行をするための手順

    1. 作業前後のバックアップ
    2. スキーマの変更

      • 移行のための過渡的なスキーマ
    3. データの移行
    4. アプリケーション移行のためのトリガーの作成
    5. アプリケーションのデプロイ
    6. 移行のためのトリガーの削除
    7. 移行のためのカラムの削除

スキーマの移行期間

  • 移行期間を設けるケース
  • 古いロジックのアプリケーションが一定期間残る
  • そのため、元のスキーマと変更後のスキーマが共存する必要がある

反復的なリファクタリング

  • アプリケーションは反復的にリファクタリングするのにDBスキーマは変更しない過ち
  • 反復的な開発は効率が良いため、技術的負債も効率良く溜まってしまう
  • DBのリファクタリングも反復的に行え

回帰テスト

  • 十分なテストケースが存在していることが前提

    • アプリケーションの機能が損われたらリファクタリングではない、破壊しているだけ
    • 機能が損われていないことを確認する方法はテストしかない

ベンチマークテスト

  • リファクタリングの結果、パフォーマンスが著しく低下するケースは珍しくない
  • パフォーマンスが低下していないことを確認する方法はベンチマークテストしかない
  • 本番に忠実な環境を用意すること

    • H/W

      • パブリッククラウドのおかげで敷居下がった
    • OS
    • テストデータの規模

マイグレーション利用のススメ

  • スキーマのバージョン管理

    • RoRのActive Recordで導入されたしくみ
    • 【補】Laravelでもおなじみ
    • 制限: バージョン分岐ができない
  • 戻す場合のロジックもテストすること
  • バックアップじゃダメなの?

    • ダメ
    • データも巻き戻ってしまう

トリガーを使って2つのテーブル間で同期を取る

  • 移行期間中、新旧テーブルのデータの整合性を確保するために使う

    • 循環に注意
    • 移行が完了したらトリガーを削除する
    • トリガーのテストも忘れずに

リファクタリングの種類

  • よりよいDB設計とは
  • どのようなリファクタリングで改善できるのか

インデックスの追加・削除

  • 軽微

    • クエリ書き換え生じない
  • テーブルが持つ論理的な意味が変更されうることに注意

    • 主キーやユニークインデックスによる一意性制約の導入/削除
  • ベンチマークテストで性能劣化のなきことを確認せよ

カラム名の変更

  • 過渡

    • 異なる名前で同じデータを持ったカラムを2つ持たせる
    • 行単位のトリガーで同期

      • MySQLなどの製品でサポート

NOT NULL制約の導入

  • 1NFにするために後からでもNOT NULLをつけることは大切

    • あるいはリレーション分割
  • NOT NULLをつけるにあたり、既存のデータにNULLが含まれていたら若干の調整が必要

    • NULLだった個所の値がデフォルト値でもNULLでも動くようにクエリを書き換える

主キーの定義変更

  • 変更が必要になるケース

    • 主キーが既約ではない場合
    • 主キーから別のカラムへの関数従属性がなくなってしまった
    • サロゲートキーからナチュラルキーへの変更、あるいはその逆

無損失分解

  • 移行期間が必要な場合は面倒

    1. 元のテーブルを残しつつ新しいテーブルを作成
    2. 双方のテーブルでデータの同期

      • トリガー
      • カスケード

テーブルの垂直分割と統合

  • 複数のテーブルで直交性が満たされていない場合、テーブルの統合が必要

    • 【補】 マスタの名寄せ的な

コラム: 関連テーブルの実態

  • 1:N -> M:N
  • 2段階のリファクタリングのショートカットと考えられる

    1. 主キーを変更して行持ち
    2. 第2正規化

リファクタリングのためのベストプラクティス

  • リファクタリングに強い
  • リファクタリングがあまり必要にならない

正規化と直交性

カラムではなくテーブルを追加する

  • カラムを追加する前に熟考せよ:

    • カラムの初期値はあるか
    • 主キーに対して関数従属しているか
  • これらを満たすならカラムを追加して問題ない
  • テーブルを追加するというアプローチも

    • メリット

      • 既存のテーブルを変更しなくてよい
    • デメリット

      • JOIN増える

        • 内部表に対して主キーでアクセスできる実行計画ならば、パフォーマンスペナルティは存外小さい

SELECT * を使わない

  • 1NF崩れる

    • 順序を持ち込むことにほかならないため

アプリケーションを疎結合に

  • データへアクセスするロジックを共通化する

    • アプリケーション側の修正個所が少なくなるよう
      • DAO: Data Access Object
      • 【補】 Table Data Gatewayとか