WEB+DB PRESS plusシリーズ理論から学ぶデータベース実践入門
―― リレーショナルモデルによる効率的なSQL

書籍の概要

この本の概要

本書は,DBを使ったアプリケーション開発経験があるエンジニアを対象に,リレーショナルモデルを理解し,より効率的にDB設計を行い,適切にSQLを使いこなすために必要な知識をまとめています。SQLとリレーショナルモデルの関係から述語論理,正規化理論,SELECTの詳しい解説,アプリケーション開発におけるデータ構造,リファクタリング,トランザクションまで理論と実践を併記して解説します。SQLを改めて勉強し直したい人,リレーショナルモデルについてより理解したい人に役立つ必携の1冊です。

目次

第1章 SQLとリレーショナルモデル

1.1 そもそもSQLって?

  • リレーショナルモデルを知らなくてもSQLは書ける?
  • RDBはリレーショナルモデルを正しく実践してこそ真価を発揮する!

1.2 リレーショナルモデル

  • リレーションの定義
  • 集合とリレーショナルモデル
    • 集合とは
    • リレーショナルモデルとNULL
    • 有限集合と無限集合
  • リレーションの演算
    • 制限(Restrict)
    • 射影(Projection)
    • 拡張(Extend)
    • 属性名変更(Rename)
    • 和(Union)
    • 積/交わり(Intersect)
    • 差(Difference)
    • 直積(Product)
    • 結合(Join)
  • コラム 要素にNULLが含まれていると……
  • クロージャという性質
  • リレーショナルモデルにおけるデータ型
    • データ型と変数
    • ドメインとは

1.3 SQLにおけるリレーション操作

  • SELECTの基本形
  • コラム 拡張の評価順
  • INSERT(挿入)
  • コラム Relvar
  • DELETE(削除)
  • UPDATE(更新)

1.4 SQLにあってリレーショナルモデルにないもの

  • 要素の重複
  • 要素間の順序
  • リレーションの更新
  • トランザクション
  • ストアドプロシージャ
  • NULL

1.5 まとめ

  • コラム リレーショナルモデルは古典的か

第2章 述語論理とリレーショナルモデル

2.1 述語論理とリレーショナルモデル

  • 命題
  • 命題論理
    • 結合子
    • 真理関数の真理値
  • トートロジーと定理
    • トートロジー
    • トートロジー=定理
  • 命題論理と公理系
    • 公理
    • 公理系のサンプル
    • 背理法についての追記
    • 公理系を用いた証明のコツ
    • きわめて厄介なPrinciple of explosion
  • コラム プリミティブな演算子
  • 命題論理の限界と量化
    • 命題論理の限界
    • 量化
  • 量化子と述語論理
    • 述語論理
    • 量化子とともに用いる束縛変数
    • 量化子を伴わない自由変数
  • 述語論理と集合論
    • 述語と集合は等価に置き換えが可能
    • 集合の包含関係
    • 集合と要素の包含関係の違い
  • 述語論理の公理系
    • 述語論理の公理系の導出規則
  • ドメイン
  • 一階述語論理
  • 二階述語論理
  • リレーションの真の姿
    • リレーションの演算は論理演算
  • 閉世界仮説
  • 矛盾したDBは役に立たない
  • コラム リレーショナルモデルの限界

2.2 リレーションの演算と述語論理

  • 制限(Restrict)
  • 直積(Product)
  • 結合(Join)
  • 積(Intersect)
  • コラム 結合と制限
  • 和(Unoin)
  • 差(Difference)
  • 射影(Projection)
  • 属性名変更(Rename)
  • 拡張(Extend)
  • コラム 外部結合について

2.3 まとめ

第3章 正規化理論(その1)―― 関数従属性 ――

3.1 なぜDB設計は重要なのか

3.2 正規化

  • リレーショナルモデルを補完する理論
  • 異常を防ぐことができる
    • 異常が生じた例
    • リレーションの設計が常識的におかしい
    • なぜ異常が起きるのか
    • 異常を起こす原因は重複

3.3 正規形

  • 正規形の種類
  • 第1正規形(1NF)
    • カラムや行の順序
    • 重複する行をなくす
    • NULLが含まれてはいけない
    • 値のアトミック性
  • コラム 列の値はスカラであるべき?
    • 繰り返しグループ
  • 候補キーとスーパーキー
  • 関数従属性(FD)
  • 第2正規形(2NF)
    • 無損失分解
  • 第3正規形(3NF)
  • ボイスコッド正規形(BCNF)
  • コラム 候補キー内部に自明ではない関数従属性は存在しないのか

3.4 まとめ

第4章 正規化理論(その2)―― 結合従属性 ――

4.1 結合従属性(JD)

  • 結合従属性は無損失分解が可能
  • 関数従属性は結合従属性の一種である
  • 暗黙的な結合従属性
  • 非キー属性と結合従属性
  • コラム なぜ非キー属性があると,候補キーを無損失分解可能な結合従属性が存在しないのか

4.2 結合従属性による正規化(4NF~6NF)

  • 第4正規形(4NF)
  • 第5正規形(5NF)
    • 接続の罠
    • 直積と結合従属性
    • 結合従属性を発見するのは難しい?
  • 第6正規形(6NF)

4.3 まとめ

第5章 リレーションの直交性

5.1 リレーションの直交性と重複

  • レプリカ
  • 同じ型を含むリレーション
  • 見出しの一部だけが同じリレーション

5.2 リレーション直交化のための戦略

  • 正規化
  • 属性(カラム)の名前を統一する
    • 命名規則を統一する
    • 主語を含める
  • アプリケーションの整合性
  • すべてを直交化する必要はない

5.3 重複を解消することのメリット

  • 異常を防げる
  • 必要なデータがどこにあるかが明確になる
  • クエリの記述が宣言的になる
  • 不要な無損失分解が必要ない
  • 複雑な制約が必要ない
  • アプリケーションのコードに無駄がなくなる
  • 性能が向上する

5.4 まとめ

第6章 ドメインの設計戦略

6.1 ドメイン

  • ドメインとは
  • 集合の要素

6.2 ドメインの設計戦略の概要

  • すべては恣意的な選択
  • アプリケーションの要求から生まれる
    • 適切なDB設計に必要なこと
    • ドメイン駆動設計
    • DBのリファクタリング
  • データの本質を見極める
    • 数値に文字列カラムを割り当てる例
    • DBは本質的なデータを扱うようにする
  • 属性(カラム)の名前

6.3 IDを設計するという考え方

  • 現実世界の物体や概念を表す手段
    • ナチュラルキーとサロゲートキー
    • どちらを使うべきか
    • ナチュラルキーの使いどころと問題点
    • サロゲートキーの使いどころと問題点
  • リレーショナルモデルにおけるキー
  • 意味を含んだID
  • コラム 紙の呪縛
  • IDの欠陥は波及する
  • 色,長さ,重さなどの性質を表す属性

6.4 SQLによるドメインの表現

  • 適切なデータ型を選ぶ
  • 述語を制約で表現する
  • ドメインをテーブルとして表現する

6.5 まとめ

第7章 NULLとの戦い

7.1 NULL

  • NULLとは
  • 3値論理(3VL)
    • NULLは演算を台無しにする
    • 検索結果が意図しないものになる可能性
    • NULLによる第3の論理値
    • 想像以上に厄介な3VL
  • 3値論理の限界
    • Unknownと曖昧さ
  • コラム 量子コンピュータとNULL
  • NULLは閉世界仮説に反する
  • オプティマイザへの弊害

7.2 NULL対策

  • テーブルを正規化する
  • 誤ったNULL対策
  • COALESCE関数
  • 空文字列の扱い
  • NULLを使っても良いケース

7.3 まとめ

第8章 SELECTを攻略する

8.1 SELECTはSQLの心臓部

  • SELECTの本質
    • SELECTの強大さ
    • データを取得する唯一の手段
  • SELECTの基本構造

8.2 SELECT七変化

  • 集約関数
    • 関数の有無だけで意味が変わる
    • COUNTの特殊性
    • GROUP BYによる集約の書式
  • サブクエリ
    • テーブルサブクエリ
    • スカラサブクエリ
    • 行サブクエリ
  • ビュー
  • UNION
  • 組み合わせは自由

8.3 リレーショナルではない操作

  • リレーショナルな操作のおさらい
  • ソート
  • 明示的に定義されていないカラム
  • ストアドファンクション(ユーザ定義関数)
  • コラム 集約とGROUP BY
  • リレーショナルではない操作の扱い方

8.4 インデントでSELECT文を読みやすくする

  • インデントのルール

8.5 まとめ

第9章 履歴データとうまく付き合う

9.1 履歴データの問題点

  • 世界は履歴データで溢れている
  • 履歴とリレーショナルモデルの相性問題
  • 履歴データの具体例
  • 履歴データの何が問題になるのか
    • リレーションと時間軸の直交性
    • NULLの可能性
    • 特定の行だけ意味が違う

9.2 履歴データに対する解決策

  • リレーションを分割する
  • 最もシンプルな分割方法
    • 外部キーが使用できない
    • 2つのテーブルの整合性
  • 重複した行を許容する
  • サロゲートキー
  • 未来の価格はどうすべきか

9.3 履歴データのアンチパターン

  • フラグを立てる
  • コラム フラグのお化け
  • 手続き型として実装する
  • コラム テーブルを分けたときの物理的なメリット

9.4 まとめ

第10章 グラフに立ち向かう

10.1 グラフの構造

  • ノード,エッジ
  • 隣接
  • 次数
  • 歩道,小道,道
  • 多重辺
  • ループ
  • 閉路
  • 連結
  • 部分グラフ
  • カットセット,ブリッジ
  • エッジの向きと重み
  • グラフの応用例

10.2 グラフの種類

  • 一般グラフ
  • 単純グラフ
  • 連結グラフ/非連結グラフ
  • 完全グラフ
  • 正則グラフ
  • 平面グラフ
  • 有向グラフ/無向グラフ
  • 重み付きグラフ
  • ツリー(木)

10.3 SQLとグラフの相性問題

  • グラフに対するクエリ
  • 無向グラフを表現できるか
  • 有向グラフを用いた表現
  • リレーショナルな視点でモデルを理解する
    • 行列を用いた表現
  • グラフに対するクエリ
  • 手続き型による解法
  • グラフDB
  • コラム FlockDB
  • そのほかの問題

10.4 ツリー(木)

  • ツリーはグラフの一種
  • コラム ディレクトリのハードリンクが作成できない理由
  • 隣接リストモデル
    • NULLが許容される理由
  • 経路列挙モデル
  • 入れ子集合モデル
    • 入れ子集合をテーブルで表現する
    • リレーショナルモデルと相性が悪い理由
  • クロージャテーブル
  • ツリーとSQLに関する考察

10.5 まとめ

第11章 インデックスの設計戦略

11.1 インデックスの働き

  • RDBのインデックス
  • インデックスの左端と範囲検索
  • セカンダリインデックスの更新

11.2 インデックスの種類

  • ハッシュインデックス
  • 全文検索インデックス
    • 形態素解析
    • Nグラム
  • Rツリーインデックス
  • 関数インデックス
  • ビットマップインデックス
  • コラム クラスタインデックス

11.3 パーティショニング

  • パーティショニングとは
  • パーティショニングが適しているケース
  • パーティショニングと一意性制約
  • パーティショニングについてよくある誤解

11.4 リレーショナルモデルとインデックス

  • インデックスはリレーショナルモデルの一部ではない
  • 正規化とインデックス
    • カラム数が絞られる
    • 問題児NULL

11.5 指令:最適なインデックスを探せ!

  • 必要なインデックス
  • インデックスのアクセス特性
  • インデックスが使用される構文
    • WHERE句
    • JOIN
    • 相関サブクエリ
    • ソート
    • カヴァリングインデックス
    • ORとインデックス
  • 最適なインデックスを探すための戦略
    • インデックス ≠ 候補キー
    • カラムの並び順
    • カーディナリティ
    • 最適な組み合わせを探す
    • 難しい作業に立ち向かう
    • 真の最適解にこだわらない
  • コラム こんなインデックス設計はゴミ箱行きだ!

11.6 まとめ

第12章 Webアプリケーションのためのデータ構造

12.1 キャッシュという考え方

  • メリット/デメリット
    • メリット
    • デメリット
  • DBアプリケーションにおけるキャッシュ
  • キャッシュはあくまでもキャッシュ
  • キャッシュとして使うための要件
  • キャッシュすべきデータの種別
    • キャッシュすべきではないデータ
    • キャッシュが可能なデータ

12.2 キャッシュの実装方法

  • NoSQLをキャッシュとして使う
    • 論理データはRDBで管理する
    • データ同期の際の注意点
  • コラム NoSQLでRDBは置き換えられるか?
  • テーブルをキャッシュとして使う
    • 集計テーブル
    • 結合済みのデータ
    • ディスクI/Oを削減できる
    • ソートとの相性が良い
    • NewSQLとの相性が良い
    • タグ
  • コラム 転置インデックスを使用して検索を高速化する

12.3 スケールアウト

  • レプリケーション
    • レプリケーションのしくみ
    • スレーブへの問い合わせ方式
    • データの論理的整合性と非同期レプリケーション
  • シャーディング
    • シャーディングのしくみ
    • シャーディングの最大の問題点
    • NoSQLのシャーディング

12.4 まとめ

第13章 リファクタリングの最適解

13.1 リファクタリング

  • DBのリファクタリングは大変
  • マルチアプリケーションにおけるDB環境
  • なぜリファクタリングが必要なのか
  • リファクタリングの手順
  • スキーマの移行期間
  • 反復的なリファクタリング
    • 回帰テスト
    • ベンチマークテスト
    • マイグレーション利用のススメ
    • トリガーを使って2つのテーブル間で同期を取る

13.2 リファクタリングの種類

  • インデックスの追加・削除
  • カラム名の変更
  • NOT NULL制約の導入
  • 主キーの定義変更
  • 無損失分解
  • テーブルの垂直分割と統合
  • コラム 関連テーブルの実態

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

  • 正規化と直交性
  • カラムではなくテーブルを追加する
  • SELECT * を使わない
  • アプリケーションを疎結合に

13.4 まとめ

第14章 トランザクションの本質

14.1 トランザクション

  • トランザクションの機能
    • 同時実行制御
    • クラッシュリカバリ
  • トランザクションの鍵,スケジュール
    • 処理の並列化は必要不可欠
    • 同時自動制御の鍵,スケジュール
  • 「データの正しさ」の定義
  • スケジューラの性能

14.2 トランザクションの特徴

  • ACIDとは
    • 原子性(Atomicity)
    • 一貫性(Consistensy)
    • 分離性(Isolation)
    • 永続性(Durability)
  • さまざまな異常
    • ロストアップデート
    • インコンシステントリード
    • ダーティリード
    • ノンリピータブルリード
    • ファントムリード
  • スケジュールとロック
  • デッドロック
  • トランザクションの分離レベル
  • MVCC
  • クラッシュリカバリ
    • DBサーバのコンポーネント

14.3 トランザクションとデータモデルの融合

  • リレーショナルモデルとACIDの「C」
  • リレーショナルモデルと異常
  • 正規化と直交性
  • 制約
    • データモデルだけでは不十分である理由
    • 制約を活用してデータを守る
    • NOT NULL
    • 一意制約
    • CREATE TYPE
    • CHECK制約
    • 外部キー制約
    • トリガー

14.4 まとめ

著者プロフィール

奥野幹也(おくのみきや)

栃木県在住のギーク。フリー(自由な)ソフトウェアの普及をライフワークとしている。KDEを愛用。仕事ではMySQLのサポートに従事。著書に『エキスパートのためのMySQL[運用+管理]トラブルシューティングガイド』『MySQL Cluster構築・運用バイブル』(ともに技術評論社)がある。
Blog:漢(オトコ)のコンピュータ道