はじめに
今回は達人に学ぶDB設計 徹底指南書を読了したので、良かったところや悪かったところなどをまとめていこうと思います。
購入するか悩んでいる方やこちらの本を気になっている方の参考になれば良いと思います。
良かったところ
- 「論理設計」と「物理設計」のそれぞれに解説があるので、偏った学びではなく全体的に満遍なく学習することができる一冊。
- テーブルの表や図などが至る所に使われていて内容を理解しやすかった。
- トレードオフについてや、バッドノウハウ、グレーノウハウなどが紹介されていて、DB設計を行う際に
気をつけておきたいことが記載されていました。(これを知らないと私はあたかもバッドノウハウが正しいと言わんばかりにバッドノウハウなどを使っていたと思います。) - DB設計で失敗すると開発全体の失敗の可能性があるということで、設計がどれほど難しいが重要な工程であるかを学習することができる。
悪かったところ
- 初学者には内容が難しいところ。
図や表で説明をされているのですが、そもそも設計についての知識がない場合だとなにを言っているかを理解するのは正直難しいかなと思いました。
こちらについては読み終えた今でも理解は浅いかと思うので復習しながら少しずつ理解を深めていく必要がありそうな気がします。
学んだこと
第1章 データベースを制する者はシステムを制す
システムとデータベース
-
データ処理としてのシステム
- データベースとは、データを整合的に保持して、いつでも簡単に利用可能な状態にしておくためのシステム。
- DBMSとは、データベースを管理するためのシステム。
- データベースを持っていないシステムは存在しない。
-
データと情報
- データとは、ある形式(フォーマット)に揃えられた事実のこと。
- 情報はデータと文脈を構成して生まれる。
データベースあれこれ
-
データベースの代表的なモデル
-
リレーショナルデータベース(RDB)
- 関係データベースとも呼ばれ、現在最も広く利用されている。
- IT業界では、「データベース」と言えば、リレーショナルデータベースを指す。
- データを人間が理解しやすい二次元表の形式で管理するため、データの取り扱いが他のデータベースに比べると直感的で簡単である。
-
オブジェクト指向データベース(OODB)
- オブジェクトをデータべースに保存するために作られたのが、オブジェクト指向データベース
-
XMLデータベース(XMLDB)
- Web上でやり取りされるデータの形式にXMLが普及している。
- このXML形式のデータを扱うことのできるデータベースとして開発されたのが、XMLデータベース。
- リレーショナルデータベースが苦手とする階層構造のデータの扱いを取得する。
-
キー・バリュー型ストア(KVS)
- データをkey(識別キー)とValue(値)の組み合わせただけの単純なデータ型で表現するデータベース。
- 単純なデータ問い合わせを高速化することを目的としていて、大量データを高速に処理する必要のあるWebサービスで多く利用されている。
- その反面複雑なデータ操作は苦手である。
-
階層型データベース
- データを階層構造(木構造)で表現するデータベースのこと。
- リレーショナルデータベースより一世代前の主流データベース。
-
-
データベースのモデルが異なれば、データフォーマットも異なるし、モデルが異なれば設計技法も異なる。
-
DBMSの違いは設計に影響するか?
- 主なDBMSとして、Oracle Database, SQL Server, DB2, PostgreSQL, MySQLなどがある
- DBMSが異なっても、(基本的には)設計の方法は影響を受けない。
システム開発の工程を設計
-
システム開発の設計工程
①要件定義
システムが満たすべき機能やサービスの水準、すなわち要件を決める工程
②設計
定義された要件を満たすために必要なシステムを作るための設計を行う工程
③開発(実装)
設計書に従ってシステムを実際に作る工程
④テスト
実装によって組み上がったシステムが、本当に実用にたえる品質であるかを試験(テスト)する工程 -
システム開発は、①~④の順で行われる。
-
設計工程と開発モデル
- ウォーターフォールモデル
- 滝(waterfall)という名前が示す通り、要件定義→設計→開発→テストというように一つずつ工程を踏んで、段階的にシステムを作っていく。滝が逆流することがないように、基本的に工程が逆戻りすることはない。
- プロトタイピングモデル
- 最初に試作品を作って、ユーザーにフィードバックをもらって、それを取り入れて再度改良するということを繰り返す循環的な開発手段。
- 早い段階からシステムの具体的なイメージを開発者や顧客と共有できるので要件定義の取りこぼしや意思疎通の齟齬を防げるというメリットの一方で、何度も同じ工程を繰り返す必要があり、変更を繰り返すうちに発散して収集がつかなくなる、というリスクもある。
- 小規模のシステムに対して適用される。
- ウォーターフォールモデル
設計工程とデータベース
-
なぜデータベースが重要か
理由1
システムにおいて大半のデータ(少なくとも永続的に使用されるデータ)は
データベース内に保持される。
そのため、普通、データ設計とはデータベース設計とほぼ同義である。理由2
データ設計がシステムの品質を最も大きく左右する。ソフトウェアというのは、言ってみれば「データの流通機構」であって、どのようなプログラムが必要になるかは、どのようなデータをどういうフォーマットで設計するかに左右される。 -
DOAとPOA
- POAはプロセス(処理のことでプログラムと同義)を先に設計する方法論のことで、現在ではこの考え方は時代遅れ。
- DOAはデータ中心アプローチのこと。
- POAの欠点を克服するために登場した。
- 着眼ポイントはデータがあまり変化しない(永続的)という点。
- データの意味や形式が先に決まっていれば、複数のプログラムで共用することも容易で、業務要件の仕様変更にも柔軟に対応できるというメリットが得られる。
- システム開発においては、プログラム設計に先立ってまずデータ設計が優先される。
- データ設計(データベース設計)は、システムの品質を決める最も重要な要因といっても過言ではない。
- データ設計においてセオリーを踏み外した設計(バッドノウハウもしくはアンチパターン)を行うと、システムの機能/非機能の品質を致命的に損なうことになる。
- データベースを制する者がシステムを制す。データベースは、システムの中心であると同時にシステム開発の中心でもある。
-
3層スキーマ
「枠組み」や「構図」という意味の単語。データベース設計においては、
データベースのデータ構造やフォーマットという意味で使う。
データベース設計のステップは、このスキーマのレベルと密接に結びついている。
スキーマは、一般的に三つのレベルに分類される。-
外部スキーマ(外部モデル)= ビューの世界
- システムの利用者であるユーザーから見て、データベースがどのような機能とインタフェースを持っているかを定義するスキーマ。
- ユーザーから見える「システムの姿」の一部である。
-
概念スキーマ(論理データモデル) = テーブルの世界
- データベースに保持するデータの要素および、データ同士の関係を記述するスキーマ。
- 外部スキーマがユーザーから見たデータベースだとすれば、概念スキーマは「開発者から見たデータベース」。
-
内部スキーマ(物理データモデル) = ファイルの世界
- 概念スキーマで定義された論理データモデルを、具体的にどのようにDBMS内部に格納するかを定義するスキーマ。
- 「DBMSから見たデータベース」で、テーブルやインデックス(索引)の物理的定義を含む。
- 内部スキーマの設計を、論理設計との対比で「物理設計」と呼ぶ。
-
概念スキーマとデータ独立性
- 概念スキーマというのは、外部スキーマと内部スキーマの間に位置することで、両者の変更が互いに影響し合わないようにするための、緩衝材の役割を果たしている。
- スキーマの独立性のことを、データ独立性と呼び、外部スキーマからの独立性を論理的データ独立性、内部スキーマからの独立性を物理的データ独立性と呼ぶ。
- 概念スキーマはデータ毒陸生を保証するためにある。
-
第2章 論理設計と物理設計
概念スキーマと論理設計
-
概念スキーマを定義する設計を、論理設計と呼ぶ。
-
システムの世界では「論理」という言葉がよく登場するが、通常の「整合的で筋道が通っている」と言う意味ではなく、「物理層の制約にとらわれない」という意味で使う。
-
論理設計のステップ
①エンティティの抽出
②エンティティの定義
③正規化
④ER図の作成 -
エンティティの抽出
- エンティティとは日本語で「実体」のこと
- 現実世界に存在するデータの集合体を指す言葉で、物理的実体を伴ったものや、物理的実体を伴わないものも含まれる。
-
エンティティの定義
- エンティティは、データを「属性(attribute)」という形で保持する。(二次元表における「列」と同義)
- 「キー(ある特定の列)」を定義すること。
-
正規化
- エンティティ(テーブル)について、システムでの利用がスムーズに行えるよう整理する作業のこと。
- 更新(データの登録、変更、削除)が整合的に行えるように、エンティティのフォーマットを整理することが重要な目的。
- 正規化は、データベースの論理設計を理解する鍵と言っても過言ではない。
-
ER図の作成
- ER図は、Entity-Relationship Diagram の略。
- エンティティ同士の関係を表現する図を作成する、いわば「エンティティの見取り図」
内部スキーマと物理設計
-
物理設計のステップ
①テーブル定義
②インデックス定義
③ハードウェアのサイジング
④ストレージの冗長構成決定
⑤ファイル物理配置決定 -
テーブル定義
- 論理設計で定義された概念スキーマをもとに、それをDBMS内部に格納するための「テーブル」の単位に変換していく作業。
- 論理設計で作られるERモデルを「論理モデル」と呼ぶのに対し、このフェーズで作られるモデルを「物理モデル」と呼ぶ。
-
インデックス定義
- インデックス(索引)はリレーショナルデータベースにおいてテーブルと並んで重要な概念。
- インデックスは、なくても機能的には何の問題もないが、パフォーマンスの向上に繋がる。
-
ハードウェアのサイジング
-
「サイジング」という言葉は、「サイズ(大きさ)」に由来していて、「大きさを決める」という意味で、システム開発では2種類の意味で使う。
- 一つは、データの規模を問題にする場合で、
「システムで利用するデータサイズを見積り、それに十分な容量の記憶装置(ストレージ)を選定する」という意味。 - 一つの意味は、パフォーマンスに関わる使い方。サイズを測る対象はサーバーのCPUやメモリ。システムが十分な性能を発揮できるだけのスペックのCPUやメモリを持ったサーバを選定すること。
- 一つは、データの規模を問題にする場合で、
-
サイジングはキャパシティとパフォーマンスの2つの観点から行う。
-
データベースの性能問題の8割はディスクI/Oによって起きる。
-
データベースにおいては、データの整合性とパフォーマンスの間に強いトレードオフが存在する。整合性を高くしようとするとパフォーマンスが犠牲になり、パフォーマンスを追求すると整合性を犠牲にするという二律背反の原則。
-
キャパシティのサイジング
- データベース内に格納するデータ量は、物理的なテーブル定義およびインデックス定義が終わらなければ算出できない。この作業を実施するには、論理設計の終了が前提条件になる。ここでのデータ量には、データベース内に格納するテーブル以外にも、テキストや画像、HTML等さまざまな形式のファイル文も加算する必要がある。
-
サービス終了時のデータ増加率
- データ量というのは、システムん運用開始から、基本的には増えていくので、システムの運用終了時にデータ量がどの程度増えるかを見越しておかないと、途中でストレージの内容が足りなくなってしまう。
-
実際、データ量を正確に見積もることが難しい場合もある。
これに対しては、
①安全率を大きくとって、余裕を持たせたサイジングを行う。
②仮に後で容量が不足した場合に、簡単に記憶装置を追加できるような構成にしておく。
②のような後からの拡張性が簡単な構成を、「スケーラビリティが高い」と表現する。 -
パフォーマンスのサイジング
-
通常、システム開発では性能性要件を二つの指標を使って定義する。
-
一つが処理時間。特定の処理について「何秒いないに終了すること」といった形で定義する。
-
もう一つの要件が、スループット。これは単位時間当たりにどれだけの処理をシステムがこなせるかを示す。
-
処理時間が「どれだけ速く処理できるか」の指標で、スルートップは「どれだけたくさん処理できるか」の指標。この単位は「1秒あたり仕事量」を示すTPS(Transaction Per Second)という指標を使う。
この二つの要件を、要件定義の段階で決めておく必要がある。 -
精度の高いサイジングは難しいので、必ず実施時には安全率をかけ、スケーラビリティの高い構成を組むこと。
-
サイジングは失敗すると被害が大きい割に、制度を高く行うのも難しいという、悩ましいタスクである。
-
-
ストレージの冗長構成
- ストレージは、データベースのデータを保持する媒体で、一般的にはHDDを使用する。
- データベースに保管されるデータは、業務の基幹データなので、これを失うことは絶対に許されない。
- そのため、「RAID」を使用して、可能な限り高い耐障害性を持つようにシステムを構築する必要がある。
-
RAID(Redundant Array of Independent Disks)
- 日本語に訳すと「独立したディスクの冗長配列」
- 複数のディスクを束ねて仮想的に一つのストレージとする技術で、この単位でまとめられたディスクをRAIDグループと呼ぶ。
- 基本的な考え方は、複数のディスクに同じデータを書き込んで冗長化することで、そのうちの一本が壊れても残りのディスクが生きていればデータを保全できるようにする、というもの。
- RAIDはシステムの信頼性と性能を共に改善できる技術。
-
RAID0
- 別名ストライピング
- データを異なるディスクに分散して保持すること。
- ディスクのうち1本でも故障したらデータが失われるため冗長性はまったくない。
-
RAID1
- 別名ミラーリング。
- 2本のディスクにまったく同じデータを持つ。
そのため、冗長性は1本だけの場合に比べて2倍になり、2本のディスクが同時に壊れない限り、データは保持される。信頼性は1本のときより上がる。 - データは分散されないので、性能は1本の場合と変わらない。
-
RAID5
- パリティ分散と呼ばれる方式。
- 最低3本で構成し、データとともに「パリティ」と呼ばれる誤り符号訂正符号を分散して格納する。
- ディスクが壊れたとしても、パリティから実データを復元することが可能。
1本までならばどのディスクが壊れてもデータを保全できる。
(2本のディスクが同時に壊れると、データが失われる。)
-
RAID10
- 別名を「RAID1+0」とも呼び、名前が意味するとおり、RAID1とRAID0を組み合わせたもの。
- RAID1とRAID0の「いいとこどり」を目論んだ方法で、RAID1の高信頼性とRAID0の高速性を両立させる。
- 欠点は、必要になるディスクの本数が多いため、コストが高いこと(最低でも4本が必要になる)
-
データベースのRAIDは少なくともRAID5で構成し、お金に余裕があればRAID10。RAID0は論外。
-
ファイルの物理配置
- データベースのストレージの冗長構成が決まったら、物理設計の最終ステップは、
データベースのファイルをどのディスク(またはRAIDグループ)に配置するかを考える。
①データファイル
②インデックスファイル
③システムファイル
④一時ファイル
⑤ログファイル
開発者が意識するのは、①データファイルと②インデックスファイルだけ。
このファイルは、「テーブル」のデータと、テーブルに付与されたインデックスのデータが格納される。
- データベースのストレージの冗長構成が決まったら、物理設計の最終ステップは、
-
データファイル
- ユーザーがデータベースに格納するデータを保持するためのファイル。
- テーブルのデータを格納するファイルであるため、業務アプリケーションがSQLを通じて参照および更新を行うファイルでもある。
-
インデックスファイル
- テーブルに作成されたインデックスが格納されるファイル。
- DBMSではテーブルとインデックスは普通異なるファイルとして管理される。
- インデックスを使うかどうかは、DBMSが内部で勝手に判断するため、ユーザーもインデックスの存在を意識することはない。
-
システムファイル
- システムファイルは、DBMSの内部管理用に使われるデータを格納する。
- 基本的に業務アプリケーションやユーザーがアクセスすることはない。
-
一時ファイル
- DBMS内部での一時的なデータを格納するために使われる。
- 処理が終了すれば削除されてなくなるので他のファイルと異なり、継続的にサイズが増加することはない。
-
ログファイル
- テーブルのデータに対する変更を受け付けた場合に一旦変更を保存するためのファイル。
-
バックアップ設計
- バックアップの基本分類
- バックアップはファイルのコピーで行う。
- 完全/差分/増分
-
主要な三つのバックアップ方式
①フルバックアップ(完全バックアップ)
②差分バックアップ
③増分バックアップ -
データベースのバックアップ設計においては、三つの方式を組み合わせていく。
(どれか一つだけ、ということは普通ない) -
①フルバックアップ(完全バックアップ)
- ある時点でそのシステムで保持されているすべてのデータをバックアップする方式。あるタイミングにおけるスナップショットを取るようなもの。
- フルバックアップには運用上の厳しい制限が課せられている。
-
②差分バックアップ
- 最後のフルバックアップ以降に変更された全てのデータをバックアップする
- バックアップ時間も短くなるほか、バックアップファイルを保管しておく
媒体の容量も小さくして節約できる。
-
③増分バックアップ
- 最後のバックアップ(フル、差分、または増分)以降に変更されたデータのみをバックアップする方式。
-
バックアップ方式にもトレードオフがあり「バックアップコストが低いほどリカバリコストは高い。」
-
バックアップ方式は、「フルバックアップ+差分バックアップ」または「フルバックアップ+増分バックアップ」の組み合わせが一般的。
-
リカバリ設計
- リカバリとリストア
- 「バックアップファイルを戻す」作業を「リストア」、そのファイルに対して、トランザクションログを適用して変更分を反映する作業を「リカバリ」と呼ぶ。
- リストアおよびリカバリの手順
1.フルバックアップのファイルをデータベースに戻す。→ リストア
2.差分または増分バックアップしていたトランザクションログを適用する。→ リカバリ
3.データベースサーバーに残っているトランザクションログを適用する。→ ロールフォワード
第3章 論理設計と正規化〜なぜテーブルは分割する必要があるのか?
テーブルとは何か?
- テーブルとは、共通点を持ったレコードの集合のこと。
- テーブル名はすべて複数形または複数名詞で書く。
- テーブルは、形だけ二次元表を満たしていれば良い、というものではなくそれ自身が現実世界と結びついた意味を持っていなければならない。
テーブルの構成要素
- 行と列
- 通常の表と同様に、テーブルにおいても横と縦のデータの組みを「行」と「列」と呼ぶ。あるいは「レコード」と「カラム」という呼び方もする。
- キー
- リレーショナルデータベースのテーブルになくてはならないものの一つが「キー(key)」。
- 主キー(primary key)
- テーブルにおいて必ず一つ存在しなければならず、かつ一つしか存在しない。
- その値を指定すれば、必ず1行のレコードを特定できるような列の組み合わせ。
- 外部キー(foreign key)
- 2つのテーブル間の列同士で設定するもの。
- 外部キーの役割は、テーブルに対して一種の「制約(constraint)」を課すこと。この制約を「参照整合性制約」と呼ぶ。
- 外部キーは人間の親子関係と同じ。
- 外部キーが設定されている場合、データの削除は子から順に操作するのが吉。
- 制約
-
テーブルには、いくつかの種類の制約を付けることができる。
-
①NOT NULL制約
- NOT NULL制約が設定された列にNULLのデータを登録しようとしたり、
NULLに更新しようとしたりした場合、そのSQL文はエラーとなる。 - テーブル定義において、列には可能な限りNOT NULL制約を付加する。
- NOT NULL制約が設定された列にNULLのデータを登録しようとしたり、
-
②一意制約
- ある列の組ついて一意性を求める制約。
- 主キーと似ているが、主キーがテーブルにつき一つしか設定できないのに対し、一意制約は何個でも設定できる。
-
③CHECK制約
- ある列の取りうる値の範囲を制限するための制約。
- テーブルや列の名前に日本語はご法度。
- 名前の先頭をアルファベッド以外で初めてはいけない。
- 同じ名前を持つテーブル、同じ名前を持つ列は存在してはならない。
-
正規化とは何か?
- 正規形の定義
- 正規形とは、データベースで保持するデータの冗長性を排除し、一貫性と効率性を
保持するためのデータ形式。 - 正規形のレベルは第5まであるが、普通は第3正規形まで理解すれば十分。
- 正規形とは、データベースで保持するデータの冗長性を排除し、一貫性と効率性を
第1正規形の定義〜スカラ値の原則
- 第1正規形の定義
- 第1正規形の定義とは「一つのセルの中には一つの値しか含まない」というもの。
- 一つのセルに一つだけの値が含まれているとき、この値のことを「スカラ値(scalar value)」と呼ぶ。sucalarは「単一の」と言う意味の英単語。
- 主キーは一部であってもNULLを含んではならない。
- なぜ一つのセルに複数の値を入れてはダメなのか?〜関数従属性〜
- セルに複数の値を許せば、主キーが各列の値を一意に決定できないから。
これは主キーの定義に反している。
- セルに複数の値を許せば、主キーが各列の値を一意に決定できないから。
第2正規形〜部分関数従属
- 第2正規形の定義
- 主キーの一部の列に対して従属する列がある場合、この関係を部分関数従属と呼び、これに対して、主キーを構成するすべての列に従属性がある場合を、
完全関数従属と呼ぶ。第2正規形とは、テーブル内で部分関数従属を解消し、
完全関数従属のみのテーブルを作る。 - 第2正規形は、部分関数従属を解消することで得られる。
- 部分関数従属を解消する手段も決まっていて、その方法はテーブルの分割をする。
- 主キーの一部の列に対して従属する列がある場合、この関係を部分関数従属と呼び、これに対して、主キーを構成するすべての列に従属性がある場合を、
- 無損失分解と情報の保存
- 第2正規化は、必ず正規化する前の状態にテーブルを戻すことができるようになっていて、こういう操作を「可逆性(reversible)」と呼ぶ。
- 情報を完全に保存したままテーブルを分解する操作のことを、
無損失分解と呼ぶ。 - 正規化の逆操作は結合。
第3正規形〜推移的関数従属
- テーブル内部に存在する段階的な従属関係のことを、推移的関数従属と呼ぶ。
- 第3正規形の定義
- 推移的関数従属によるデータ登録時の不都合を解消するには、第2正規化のときと同じように、テーブルを分割することで、それぞれの関数従属の関係を独立させる。
ボイスーコッド正規形
- 3次と4次の狭間
- 第3正規形をより厳密にしたものと考えられるから、ボイスーコッド正規形は、非公式にですが「第3.5正規形」とも呼ばれる。
- ボイスーコッド正規形への分解時には気をつけないと非可逆な分解を行なってしまうことがある。
第4正規形
- 第4正規形の定義
- 第4正規形は、独立な多値従属性が複数存在するテーブルを分割することで作られる。
- 複数の多値従属性を一つのテーブルで表現しようとするのは、正味な話、かなり無理のある設計。
「関連エンティティを作る場合は、そこに含まれる関連は、一つだけにすること」という設計上のルールが必要だ、ということ。
第5正規形
- 第5正規形の定義
- 関連と関連エンティティを一対一対応になるようテーブル分割することで作られる。
- 第5正規形の適用によるテーブル分割と、多対多の関係を解消するための中間テーブルの作成は、異なる問題を解決する為のものだが、結果として似たようなテーブル構造をもたらすことがある
正規化についてのまとめ
- 正規化の三つのポイント
- 正規化とは更新時の不都合/不整合を排除するために行う
- 正規化は従属性を見抜くことで可能になる
- 正規形はいつでも非正規形に戻せる
- 正規化は常にするべきか?
- 第3正規形までは、原則として行う。
- 関連エンティティが存在する場合は関連エンティティが1対1に対応するよう注意する。
- 正規化を行うほど、利点がある。
- データの冗長性が排除され、更新時の不整合を防止できる。
- テーブルの持つ意味が明確になり、開発者が理解しやすい。
- 欠点
- テーブルの数が増えるため、SQL文で結合を多用することになり、
パフォーマンスが悪化する。
- テーブルの数が増えるため、SQL文で結合を多用することになり、
第4章 ER図〜複数のテーブルの関係を表現する
テーブルが多すぎる
- テーブル(エンティティ)の数が増えていくと、テーブル同士の関係がわかりにくくなり、設計に支障をきたす。
- この問題を解決するため、テーブル同士の関係を記述する道具がER図(Entity-Relationship Diagram : 実体関連図)。
- ER図の代表的な書き方に、IE(Information Engineering)表記法とIDEFIXがある。
- リレーショナルデータベースにおけるテーブル間の関係は、基本的に「1対多」
「多対多」の関係は、「1対多」の関連に分解する。
テーブル同士の関連を見抜く
- ER図を描くとき、最初に着目するポイントは、あるテーブルの主キーが、他のテーブルに列として含まれているかどうか、という点。
- 1対1、1対多、多対多
- 1対1
- あまり見かけない。
- 二つのテーブルのレコードが1対1に対応するということは、
要するに二つのテーブルの主キーが一致するケースであり、そうであれば普通は一つのテーブルにまとめてしまっても問題ない。 - 正規化の過程でこのような1対1のテーブルが作られることはない。
- 1対多
- 最もよくある関連のタイプ。
- 基本的に正規化によって生まれる関連はこのカテゴリーに属す。
- 「1対多」と「0または1対多」に分かれるが、一般的にはこの二つのサブカテゴリをまとめて「1対多」と呼ぶことが多い。
- 「多」の側についても、「0以上」「1以上」の場合があるが、こうした細かい区別についても、ER図で表記することが可能。
- 多対多
- 業務要件からテーブルを作っていくと、この多対多の関連を持ったテーブル群ができあがることがある。
- リレーショナルデータベースのお約束として、この多対多の関連は作ってはならない。
- 1対1
第5章 論理設計とパフォーマンス〜正規化の欠点と非正規化
正規化の功罪
-
正規化とSQL(検索)
- 正規化されたテーブル群であっても、SQL文で結合を使うことによって、
得たい結果を自由に得ることができる。 - 非正規化テーブルならば、SQLで結合を使わずに済む。
- 正規化されたテーブル群であっても、SQL文で結合を使うことによって、
-
正規化とSQL(更新)
- 正規化を行なっていると変更箇所が1箇所で済むため、更新処理のコストが低く、かつ一定である
-
正規化と非正規化、どちらが正解なのか?
- 正規化は必須であり、いかなる理由があろうとも非正規化するべきではない、という原理的主義な立場から、最初から非正規化を論理設計の中に織り込む「現実主義的」な立場まで、正規化に対する態度は人により様々。
- 正規化と検索SQLのパフォーマンスは強いトレードオフの関係にあるということ。
- 厳しく正規化すればパフォーマンスが悪化し、パフォーマンスを求めて非正規化すれば、
データ不整合が発生しやすくなる。 - 正規化の次数が低いほど検索SQLのパフォーマンスは良いが、データ整合性は低く、正規化していくほどパフォーマンスが低下する代わりにデータ整合性が高くなる。
- 非正規化は最後の手段。最初は必ず正規化し、正規化の次数は高ければ高いほど設計という観点からは望ましい。
非正規化とパフォーマンス
-
サマリーデータの冗長性とパフォーマンス
- 正規化、すなわち冗長性排除によって引き起こされる性能問題には、SQLの構文という観点から見ると、大きく2種類のパターンに分けられる。
- ①サマリーデータの冗長性排除によるパターン
- ②選択条件の冗長性排除によるパターン
-
結合しないSQLを作るためのテーブル設計
- サマリーデータを冗長に保持すると正規形に違反するが、検索を高速化できる。
-
選択条件の冗長性とパフォーマンス
- 選択条件を冗長に保持すると正規形に違反するが、検索を高速化できる。
- 正規化は、可能な限り高次にすることが大原則
- それでもなお、実務における論理設計では性能のために非正規化が必要になる時がある
- いかにSQLのパフォーマンスチューニングを行なったとしてもテーブル構成が正規化された状態では限界がある
- データ構造がプログラムのコードを決定するのであって、その逆はない
冗長性とパフォーマンスのトレードオフ
-
非正規化が更新不整合のリスクを増やす。
- ①非正規化は、検索のパフォーマンスは向上させるのが更新のパフォーマンスを低下させる。
- ②データのリアルタイム性(鮮度)を低下させる
- ③後続の工程で設計変更すると、手戻りが大きい。
-
更新時のパフォーマンス
- データのリアルタイム性
- 反映周期が短ければ短いほど、システムへかかる負荷は高くなり、性能問題も起きやすくなる。
- ユーザーからは短ければ短いほど嬉しいが性能性の問題も配慮しなければならないので両者のバランスが取れる平均点を見つけ出さなければならない。
- データのリアルタイム性
-
改修コストの大きさ
- システム改修コストの大きさ
- DOAの大原則のため、データモデルの変更は、コードベースの修正に比べて、非常に改修コストが大きくなる。
- 論理設計をする際には、「システムの品質は(ひいては開発が成功するかどうかは)今ここで決まる!」という気概を持って臨む必要がある。
- システム改修コストの大きさ
-
残念なことに、論理設計には物理設計の知識が必要である。
第6章 データベースとパフォーマンス
データベースパフォーマンスを決める要因
-
インデックス
- インデックスは、SQLチューニングの手段として非常にポピュラーで、これを利用しないシステムはない、
というぐらいよく使う。 - インデックスとは、プログラミング言語的な表現をすると(x,a)という形式の配列。
- xはキー値、aはそれぞれに結びつく情報 (実データか、あるいはそれへのポインタ) を意味する。
- データベースにおいてaはデータへのポインタであることが多い。
- インデックスは、SQLチューニングの手段として非常にポピュラーで、これを利用しないシステムはない、
-
統計情報
- 統計情報が重要な理由は、これがSQLのアクセスパスを決める最大の要因だから。
- DBMSは、ユーザーからSQLを受け取ると、どのような経由(パス)でデータを探しにいくのが最も有効的か、自分で判断する。
インデックス設計
-
インデックスがSQLのパフォーマンス改善のための非常にポピュラーな手段である理由は3つ。
- ①アプリケーションのコードに影響を与えない。(アプリケーション透過的)
- インデックスを使うかどうかは、DBMSが自動的に判断する。
- インデックスを使う場合、単純にデータベース側にインデックスを作成すれば良いだけで、アプリケーションプログラムの変更が必要ない。
- 「存在を意識しなくても良い」という性質を「透過性(transparency)」と呼び、もとは透明という意味で、空気のように透明でその存在を意識しなくて良い、というニュアンス。アプリケーションから見れば、インデックスは空気のように透明。
- ②テーブルのデータに影響を与えない。(データ透過的)
- インデックスは、データ透過的でもあり、インデックスを作成することでテーブルに格納されているデータの中身が影響を受けることがないし、テーブルの構造も変化することはない。
- ③性能改善の効果が大きい。
- インデックスの性能が、データ量に対して線形よりも緩くしか劣化しないため、インデックスによる性能改善は、多くの場合にデメリットをメリットが大きく上回る形で成果が出る。
- ①アプリケーションのコードに影響を与えない。(アプリケーション透過的)
-
B-treeインデックスから
- インデックスと言っても、いつくかの種類があるが、基本的にはB-treeインデックスを覚えておけば十分。
-
B-treeインデックスの長所
- B-treeの長所は、平均点の高さ。B-treeを「幅広い名手」と呼び、事実、B-treeをレーダーチャートで評価するとオール4の秀才型で総合評価で1位を取るタイプ。
-
B-treeインデックスの構造
- B-treeは、「木」という名前のとおり、木構造でデータを保持する。
- 最上位のレベルをルート、最下位のレベルをリーフ、それ以外の中間レベルを内部ノードという。
- ①均一性
- B-treeは平衡木(balanced tree)であるため、どのリーフもルートからの距離(高さ)が一定になる。これによって、どんなキー値を使っても、常にリーフまでの距離が一定になるため、検索を同じ計算量で行える。
- ②持続性
- B-treeといえども更新が繰り返されることによって性能劣化は発生する。しかし、それでもなお、B-treeの性能劣化は長期的に見ても、非常に穏やか。
- ③処理汎用性
- B-treeインデックスは、挿入、更新、削除のコストも、検索と同じくらいの探索速度となり、かつデータ量が増えても性能劣化の度合いが緩やかである。
- ④非等値性
- B-treeは、等号(=)による検索のみならず、不等号(<,>,<=,>=)やBETWEENといった範囲検の条件に対しても、高速化を可能とする。
- 否定条件(<>,!=)は、特定のノード以外のすべてののノードが該当してしまうので、B-treeによる絞り込みが効かず、まったく役に立たない。
- ⑤親ソート性
- B-treeインデックスは、構築時にキー値をソートして保持する。
- B-treeインデックスが存在する列をORDER BY句のキーとして指定した場合、ソート処理をスキップすることが可能になる。
データベースのパフォーマンスにとって鬼門の一つであるソート処理をチューニングする大きな助けになる。
B-treeインデックスの設計方針
-
B-treeのインデックスはどの列に作れば良いか?
- ①大規模なテーブルに対して作成する。
- ②カーディナリティの高い列に作成する。
- ③SQL文でWHERE句の選択条件、または結合条件に使用されている列に作成する。
-
B-treeインデックスとテーブルの規模
- データ量が少ない場合、B-treeインデックスを使うよりもフルスキャンに任せた方が高速な領域がある。
- 目安としてはレコード数が1万件以下の場合はほぼ効果がないと考えられる。
-
B-treeインデックスとカーディナリティ
- B-treeインデックスを作成する例として不適切を判断するための最も重要な情報が、カーディナリティ。
特定の列の値が、どのぐらいの種類の多さを持つか、ということを表す概念。 - B-treeインデックスを作るときは、カーディナリティの高い列を選ぶことが基本。
- 目安は、特定キー値を指定したときに、全体レコード数の5%程度に絞り込めるだけのカーディナリティがあること。
- B-treeインデックスを作成する例として不適切を判断するための最も重要な情報が、カーディナリティ。
-
カーディナリティの注意点は2つ
- ①複合列に対してインデックスを作成する場合、カーディナリティは対象の複合列の組み合わせで考える。
- ②カーディナリティーが高くても、特定の値にデータが集中しているような列は向いていない。
- カーディナリティが高い列ほどインデックスの効果が高い。ただし、値が平均的に分散しているのがベスト。
-
B-treeインデックスとSQL
- SQLで検索条件や結合条件として使用されない列にいくらインデックスを作っても無意味。
- インデックスが使用されるためには、SQLの記述方法としていくつか気をつけるべきポイントが7つある。
- ①インデックス列に演算を行っている
- インデックスを作成した列はSQLにおいて「裸」で用いるのが原則で、演算を行ってはいけない。
- ②索引列に対してSQL関数を適用している
- 理由は①と同じ
- ③IS NULL述語を使っている
- B-treeインデックスは一般的にNULLについてはデータの値とは見なさず、保持していないため、IS NULLまたはIS NOT NULL述語に対しては有効でない。
- ④否定形を用いている
- 否定形はインデックスを利用できない。これは、たとえ利用したとしても検索範囲が広すぎて役に立たないから。
- ⑤ORを用いている
- ORを用いた場合はインデックスが利用されないが、INで書き換えるこで回避できる。
- ⑥後方一致、または中間一致のLIKE述語を用いている
- LIKE述語を使うときは、前方一致検索の場合のみ索引が使用される。
- ⑦暗黙の型変換を行なっている
- データ型の異なる列値をSQLにおいて選択条件または結合条件として利用する場合、数値型⇔文字列型、文字列型⇔日付型のように、型変換を行なって型を統一する必要がある。
- 列とデータ型の異なる値を条件に指定した場合、DBMSは内部的に暗黙の型変換を行う。
その場合はインデックスは使用されなくなる。これを回避するためには、
明示的に条件に使用する値のデータ型を列のデータ型に合わせてやる必要がある。
- ①インデックス列に演算を行っている
-
B-treeインデックスに関するその他の注意事項
- DBMSは主キー制約や一意制約を作成する際、内部的にはB-treeインデックスを作成しているので、作成不要。
- B-treeインデックスを作成すればするほど、該当テーブルに対する更新性能が劣化していく。
- 運用において定期的なメンテナンスを行う、具体的にはインデックスの再構築を行うことが、性能を維持するためには望ましい方策である。
統計情報
-
オプティマイザと実行計画
- DBMSはSQLを受け取った後、直接データアクセスを行なっているのではなく、
何段階もの前作業を行なっている。 - DBMSが実行計画を決めるブラックボックス的な方法は、一見すると非効率で、どんなパスが選択されているか見えないことを不安に思うかもしれないが、実際にはデータへのアクセス方法は非常にたくさんあるうえに、コストの計算も非常に複雑であるため、これを人間が行うほうが非効率になる。
- SQLの実行計画は、DBMSが「お任せ」で選ぶ。
- DBMSはSQLを受け取った後、直接データアクセスを行なっているのではなく、
-
統計情報の設計指針
-
統計情報収集のタイミング
- データが大きく更新された後、なるべく早く。
- データの更新量が少ない場合は、統計情報を収集する意味はあまりない。
- 統計情報収集は、基本的にシステムの使用者が少ない夜間帯に実施することが原則。
-
統計情報収集の対象(範囲)
- 「大きな更新のあったテーブル(およびインデックス)」が対象
- 本当に必要なテーブルに限定する必要がある。
-
統計情報の凍結について
- 統計情報収集の設計の基本は、なるべくそれを最新の状態に保つこと。
- 実際のシステム開発においては、あえて統計情報の収集をまったく行わない、
という選択肢が有効な場合がある。 - 統計情報をあえて収集せず、特定の時点の統計情報で更新を止めることを
「統計情報を凍結する」や「統計情報をロックする」と言い、現状のものから実行計画を変化させたくない場合に凍結を行うのが望ましい。
-
第7章 論理設計のバッドノウハウ
論理設計の「やってはいけない」
- 非スカラ値(第1正規形未満)
- 配列型による非スカラ値は原則利用せず、第1正規化を守る。
- 情報は可能な限り分解して保存するのが良い。ただし意味を壊してはいけない。
ダブルミーニング
- テーブルの列は「変数」ではない
- 列は変数ではない。一度意味を決めたら変更不可。
単一参照テーブル
- 構造的に同じ別々のテーブルを一つのマスタテーブルにまとめられたものを、単一参照テーブルと呼ぶ
- テーブルにポリモルフィズムはいらない。
テーブル分割
-
テーブル分割の種類
- ①水平分割
- レコード単位にテーブルを分割すること。
- ②垂直分割
- 列単位にテーブルを分割すること。
- ①水平分割
-
集約
-
テーブル分割ではなく、テーブル分割の代替案に位置づけられる方法。
-
①列の絞り込み
- 垂直分割に対する代替案に相当する。
- 頻繁に参照される列だけを持った新しいテーブルを追加作成する。オリジナルのテーブルは残すため、分割ではない。
- 小規模なテーブルをデータマート、あるいは省略して単にマートと呼ぶ。
- マートを利用する際に注意すべき点がデータの同期の問題。
- 更新のタイミングが短いほど、オリジナルのテーブルと齟齬がある期間も短くなるので、データ精度が高く機能的にも好ましいが、更新タイミングが短いほど処理の負荷が上がり性能問題を悪化させてしまう場合もある。
-
②サマリテーブル
- 集約関数によってレコードを集約した状態で保持すること。
-
不適切なキー
- 可変長文字列は不変性がないためキーには不向き。
- 同じデータを意味するキーは同じデータ型にするべきで、、キーには固定長文字列の「コード」列が望ましい。
ダブルマスタ
- 同じ役割を果たすはずのマスタテーブルが二つ存在するようなケース。
- ダブルマスタはSQLを複雑にし、パフォーマンスを悪化させる。
- ダブルマスタが生じる直接的な理由は一つで、もともと別のシステムで利用されていたマスタ同士が、システム統合によって同じドメインに存在するようになった場合。
第8章 論理設計のグレーノウハウ
違法すれすれの「ライン上」に位置する設計
- バッドノウハウとはっきり断定することこそできないものの、無神経に使うと開発や運用に支障をきたすような、そんな毒を含んだ設計のことをグレーノウハウという。
代理キー 〜主キーが役に立たないとき
- 主キーが決められない、または主キーとして不十分なケース3つ
- ①そもそも入力データに主キーにできるような一意キーが存在しない。
- 同時に言語道断なケースで、テーブルを作ろうにも、一意キーが存在しないのでは主キーが決められない。
- ②一意キーはあるが、サイクリックに使いまわされる。
- 主キーの値がすべて使われてしまった場合に、既存の値が使われるケースで起こる。
- ③一意キーはあるが、途中で指す対象が変化する。
- 主キーの指す対象が途中で変わってしまうと言う点で、②と似ている。
- ①そもそも入力データに主キーにできるような一意キーが存在しない。
- 代理キーによる解決
- 代理キー(surrogate key)「サロゲートキー」は、入力データに最初から存在しているキーの「代理」として新たに追加するキー。
- 代理キーがそもそも理論的には不要なキーであるため、代理キーが何の役割を果たしているのかは、
ER図を一読してもわからない。 - 代理キーはそもそも論理的には不要なキーであるため、一般的な原則としては、極力代理キーの使用は避けて、自然キーによる解決策を図るべきである。
列持ちテーブル
- 配列型を使わずに配列を模倣する論理設計のこと。繰り返し項目テーブルとも呼ばれる。
- 特殊な状況でない限り、原則として列持ちテーブルは使うべきではなく、行持ちテーブル構成を採用するべき。
アドホックな集計キー
- アドホックな(場当たり的な)キーは、名前のとおり、コード体系が短いスパンで変わったり、別のコード体系が必要になったりする。そのたびに、サイズの大きいテーブルにアドホックキーを次から次へと追加すると、ただでさえ規模の大きなテーブルがますます巨大になって、パフォーマンスを劣化させる。
- 解決する手段3つ
- ①キーを別テーブルに分離すること。
- ②ビューを使うこと。
- ③GROUP BY句の中でアドホックキーを作る。
多段ビュー
- ビューとは、「クエリの缶詰」と表現し、保存がきくうえに、開けば常に新鮮なデータを取り出せる。
- ビューの短所は、パフォーマンスへ悪影響を与えることと、濫用すると帰って設計と実装を複雑なものにしてしまうこと。
- ビューは利用者からの見た目上、テーブルと同じように扱うことができるが、テーブルと違って、データを保持しない。
- ビューの使用は、原則として1段にとどめておくようにする。
データクレンジングの重要性
- リレーショナルデータベースを利用する/しないにかかわらず、システムで扱うデータをデータベースによって一元管理することは、システム化による業務効率化の第一歩。
- データクレンジングは設計に先立って行う
- 一意キーの存在しないデータは、バッドノウハウ「不適切なキー」をも生み出す。
- 名寄せをサボって複数のマスタテーブルを統合しないまま残すと、バッドノウハウ
「ダブルマスタ」を生み出すことになる。
第9章 一歩進んだ論理設計〜SQLで木構造を扱う
リレーショナルデータベースのアキレス腱
- 木構造とは?
- 名前のとおり、データが「木」の形をしているような階層状の構造。
- ノード(node)
木の結節点のこと。 - ルートノード(root node)
木が始まるトップのノード。「根っこ」という意味で、木はこのルートノードを定義上一つしか持たない。 - リーフノード(leaf node)
自分よりも下位のノードを持たない「終着点」のノード。「葉っぱ」という意味。 - 内部ノード(inner node)
ルートでもリーフでもない中間のノードのこと。 - 経路(path)
あるノードから別のノードへたどる道筋のこと。「パス」とカタカナ表記もする。
伝統的な解放〜隣接リストモデル
- 隣接リストモデル(Adjacency List Model)。
- リレーショナルデータベースで木構造を扱う方法として、最も古くから知られている方法。
- ノードのレコードに親ノードの情報(ポインタ)も持たせようとするもの。
新しい解放〜入れ子集合モデル
- 入れ子集合モデル(Nested Sets Model)
- ノードを点ではなく面積を持った「円」としてとらえる。そして、ノード間の階層関係を円の包含関係によって表す。
- 入れ子集合モデルは、木構造の検索においては大きな力を発揮するが、一方で、
更新については問題を抱えている。
もしも無限の資源があったなら〜入れ子区間モデル
- 入れ子区間モデル(Nested Intervals Model)
- 入れ子集合モデルの拡張版
ファイルシステムとしての階層
- 経路列挙モデル(Path Enumeration Model)
- ノードをディレクトリ(フォルダ)と見なし、各ノードまでの経路(path)を記述する。
- 経路列挙モデルは検索が簡単で更新が複雑。
難しかったこと
この本を通して基本的に難しかったです。難しい文で書かれていて設計についてというより日本語の検索をすることも多かったです。本で読んだだけでは理解は難しく、イメージも付きにくいと感じました。実際にやってみるときに
改めてわからないところを読み直す辞書として復習できたら理解が深まるかなと思いました。
正直、初心者にはハードルが高い一冊でした。