達人に学ぶDB設計を読んだ感想

## はじめに

スッキリわかるSQL入門を読んだ次はデータベース設計について学ぶため本書を読みました。  

こちらの記事の感想記事になります。

https://www.shoeisha.co.jp/book/detail/9784798186627

## 良かったところ

### データベース設計の全体像を学ぶことができた

- なぜデータベース設計が重要なのか

- そもそもデータベース設計とはどういう手順で何をするのか

- データベース設計をする上でどういうことに注意するべきか

まずデータベース設計における全体像を把握することが出来ました。

自分の中でデータベース設計という得体の知れないものの中身が分かり、実際にデータベース設計する際のイメージが湧きました。

### データの整合性とパフォーマンスのトレードオフについて知ったこと

本書では、トレードオフという言葉が多く登場します。

例えば、正規化ではデータの整合性とパフォーマンスにトレードオフの関係があります。データの冗長性を排除し、データの整合性を高くすればするほどデータベースのパフォーマンスは悪くなります。
理由としては、データを検索する際に、JOINを使う処理が多いと計算量が多くなりパフォーマンスが悪化するからです。

他の例としてはバックアップがあります。バックアップ頻度を上げると信頼性は高くなるが、性能は下がる、というトレードオフです。



### 設計時のアンチパターンとグレーノウハウについて知ったこと

データベース設計時に使うべきではない手法、使う際に注意しないといけない手法を学べました。

ここでは現場でよく見かけるアンチパターンと用法容量を守って使用しないといけないグレーノウハウが紹介されていました。

グレーノウハウとは本書で呼称されている用語で、アンチパターンとまではいかないものの無神経に使うと開発に支障が出るような設計のことです。

実際に、データモデリングする際はこちらに気をつけて設計していきたいところです。

## 悪かったところ

個人的には見当たりませんでした。

## 学んだこと

本書を読んで学んだことをざっと説明していきます。
正直言うと全て学びなのですが、個人的に重要だと思ったことを中心に記載していきます。



### POAとDOA

近年のソフトウェア開発ではDOA（データ中心アプローチ）という考え方が主流です。

その前にはPOA（プロセス中心アプローチ）という考え方がありました。

POAでは、プロセス単位でデータ設計を行うため、複数のプロセスで同じデータを別個に持つという冗長性が生じ、非効率でした。
この欠点を解消するため、DOAという考えが生まれました。

これにより、データのフォーマットを先に決めることで、複数のプログラムで共用することが容易になりました。
そのため、開発においても拡張性や変更に強いなどの利点があるようです。
DOAのデメリットとしては、業務プロセスよりもデータ構造が優先されるので、業務フローとソフトウェアの乖離が起きやすいことがあげられます。



### 論理設計

このフェーズでは、どんなデータをどのようなフォーマットで保存するかを決定します。

本書ではリレーショナルデータベースでの例が紹介されています。

論理設計では以下のタスクを行います。

1. エンティティの抽出

2. エンティティの定義

3. 正規化

4. ER図の作成



最終的にER図を作成するのがGOALです。



ちょっとした疑問で、論理とはどういう意味なのか気になりますが、ここでは「ハードウェアなどの物理層の制約にとらわれない」という意味で使われています。

### 物理設計

論理設計の後は物理設計を行います。

データを格納するための物理的な領域や格納方法を決定します。

物理設計では以下のタスクを行います。

1. テーブル定義

2. インデックス定義

3. ハードウェアのサイジング

4. ストレージの冗長構成決定

5. ファイルの物理配置決定



### 正規化

正規化とはテーブルを分割していき、データ更新時のデータ不整合を防止するために行います。

正規化していないテーブルだと、本来、A商社という会社名でデータ登録すべきところをa商社と誤って登録してしまうことが起きてしまいます。




**正規化のメリット**

- データ更新時のデータ不整合が無くなる

- テーブルの意味が分かりやすくなり、開発者にとって理解しやすい

**正規化のデメリット**

実際にユーザーがデータベースを使うときは正規化されたテーブルのままでは期待する情報を得られない。
情報を得るためにJOINを使った結合を使うと、計算量が増加しパフォーマンスが悪化する。
なぜならJOINの内部ではONで記述した条件を満たすようなレコードをSELECT文で検索していて、計算量が多くなるため。

**パフォーマンス悪化に対処する方法**

まず、テーブルを非正規形にすることが挙げられます。

テーブルを非正規形にすると、JOINを使わずに情報を得ることできるため、パフォーマンスは悪化しません。
本書では、これを最後の手段と述べています。
基本的には出来るだけ正規化するスタンスでいるべきです。

次に、あらかじめサマリデータをテーブルに持たせることです。

これにより正規化のレベルは下がりますが、同様にJOINを使わずに検索することができるため、パフォーマンスは向上します。

### データベースのパフォーマンス設計

**インデックス**

インデックスを定義することで、SQL文が特定のレコードをすぐに検索することができます。
インデックスには様々な種類がありますが、汎用性の高さからB-treeインデックスが頻繁に利用されます。
尖った性能は無いが、どの科目でも高得点を出すタイプと称されています。


B-treeインデックスはデータ構造の平衡木のことで、ルートノードからデータを見つけるためのリーフノードまでの高さが一定なのが特徴です。
テーブルへデータを挿入、更新、削除などを繰り返すと、ルートからリーフまでの高さがバラバラになってしまいます。

そこで、平衡木では高さのバランスを整えるための修復アルゴリズムが備わっています。ですので、探索にかかる計算量がどのデータも一定になります。



インデックスを作る列は検索条件や結合条件に使用される列に対して作ります。
すぐに条件を満たすデータを見つけるためですね。



ただ、インデックスは作りすぎてもダメです。
インデックスはテーブルとは独立したオブジェクトとしてDBMS内に保存されているので、テーブルの値が変更されると、インデックスの値も更新する必要があり、更新処理に時間がかかってしまいます。

なので、インデックスを作りすぎることは、インデックス・ショットガンというアンチパターンとして知られています。


**統計情報**

テーブルやインデックスなどのメタデータのことです。
DBMSはこのメタデータを使ってSQLのアクセスパス（実行計画）を決定します。

DBMSがSQL文を受け取ってからテーブルへアクセスするまでには以下のような手順を踏みます。

1.DBMSはSQL文を受け取る時に、パーサがSQL文の文法が正しいかチェックします。
2.チェックが終わると、SQL文はオプティマイザへ送られます。
3.オプティマイザがカタログマネージャから統計情報を受け取る。
4.オプティマイザが最短経路を選択して、SQLを実際の手続きに変換します。

ここでいう最短経路とは、最も実行コストが低いSQL文の処理手順や手段のことです。



### その他のパフォーマンスチューニング

基本的には遅いクエリがある場合はインデックスで改善をしますが、以下のようなチューニング方法もあります。

- パーティション

- ヒント句

- パラレルクエリ

- オンメモリ



### 論理設計のアンチパターン
アンチパターンとしては以下の方法があります。
その一部を紹介します。

**配列型による非スカラ値**
第一正規形の条件を満たしていないため、アンチパターンです。

**ダブルミーニング**
列の値の意味が二つ存在することです。
例えば、ある行までは身長を表すのに、途中から列の値が体重になるような運用方法です。

列は現実世界にあるエンティティの写像なので、変数よりもずっと固定的な存在でテーブルや列の意味は、容易に変更してはいけません。

**単一参照テーブル**
似た構造を持つテーブルを一つにまとめることです。
例えば、会社コードと会社名、従業員コードと従業員名の情報を一つにまとめるといった感じです。

一見、良さそうな運用だが多くの問題点を抱えています。

**テーブル分割**
テーブル分割には二種類あり、水平分割と垂直分割があります。

**水平分割**
水平分割はレコード単位でテーブルを分割します。
何百万というレコードを持つテーブルにアクセスするとSQL文のパフォーマンスが悪化します。
そこでアクセスするテーブルのサイズを小さくさせるため、この方法を用いることがあります。

利用すべきでない理由
- 拡張性に欠けること
- パーティションで似たようなことができる

**垂直分割**
垂直分割は列単位でテーブルを分割します。
こちらもアクセスするデータ量を減らしたいために行われます。

利用すべきでない理由
- パフォーマンスの向上のためにテーブルを分割しているが、正規化の理論からは分割すべき理由がない
- 以下の代替手段がある
    - 頻繁に参照される列だけを持ったテーブル（データマート）を作ること
    - データマートも作りすぎるとストレージの容量を圧迫したり、オリジナルのテーブルとのデータ同期の更新タイミングなど注意すべき問題がある

## 難しかったこと

パフォーマンスのチューニングに関するところが難しかったです。

本で読むだけだと、イメージができませんでした。

## 終わりに

本書を読んで、データベース設計の全体像を掴むことが出来ました。

今後はアウトプットしていく中で辞書がてら読み、良いDB設計ができるようにしていきたいです。