書籍概要

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 まとめ

サポート

ダウンロード

本書P.216で紹介しているサンプルコードです。
データは圧縮ファイル形式でダウンロードできます。圧縮ファイルをダウンロードしていただき,適宜解凍してご利用ください。

ダウンロード
サンプルコード

正誤表

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

(2016年4月5日更新)

P.ⅵ 目次(第2刷以降,修正済)

クロージャという性質
クロージャ・プロパティ(閉包性)

P.19 見出し(第2刷以降,修正済)

クロージャという性質
クロージャ・プロパティ(閉包性)

P.40 下から2行目

④ P∨Q・③と導出規則⑦より
④ P∨Q・と導出規則⑦より

P.40 下から1行目

⑤ Q・④と選言的三段論法より
⑤ Q・③④と選言的三段論法より

P.48 本文下から4行目

⑩と構造的には同じ
⑧(p.40)と構造的には同じ

P.83 本文下から1行目

{学科,年齢}
{学科,学年}

P.86 本文上から9行目

成り得ます
なり得ます

P.98 本文上から6行目

見て見る
見てみる

P.102 本文上から5行目

非キー属性が存在しない場合、
非キー属性が存在する場合、

P.113 リスト5.3(第2刷以降,修正済)

SELECT DISTINCT `学科` FROM t2
SELECT DISTINCT `学科` FROM t1

P.113 リスト5.4(第2刷以降,修正済)

SELECT DISTINCT `学科`, `代表番号` FROM t1
SELECT DISTINCT `学科`, `代表番号` FROM t2

P.115 本文上から4行目

図5.2(t1)の場合、
図5.3t2)の場合、

P.115 リスト5.7(第2刷以降,修正済)

UPDATE t1 SET `代表番号` = 'ww-wwww-wwww'
UPDATE t2 SET `代表番号` = 'ww-wwww-wwww'

P.115 リスト5.8(第2刷以降,修正済)

UPDATE t1 SET `代表番号` = 'ww-wwww-wwww'
UPDATE t2 SET `代表番号` = 'ww-wwww-wwww'

P.137 本文上から10行目

全射でなければならない
単射でなければならない

P.137 本文下から2行目

全射だけでは、
単射だけでは、

P.137 本文下から1行目

単射に近づける
全単射に近づける

P.138 本文上から6~7行目

そのドメインを十分に格納できるSQLの数値型を選択することで全射とし、CHECK制約でドメインの述語を表現することで単射にできます。
そのドメインを十分に格納できるSQLの数値型を選択することで単射とし、CHECK制約でドメインの述語を表現することで全射にできます。

P.145 リスト7.4

SELECT * FROM user WHERE age <> 20 OR age IS NULL
SELECT * FROM users WHERE age <> 20 OR age IS NULL

P.178 リスト8.16

リスト8.16
リスト8.14

P.178 リスト8.16

    SELECT
        department,
        (
          SELECT
              COUNT(*)
            FROM
              students
            WHERE
              department = t1.department
        ) AS COUNT
      FROM
        (
          SELECT
              DISTINCT department
            FROM students
        )
    SELECT
        department,
        (
          SELECT
              COUNT(*)
            FROM
              students
            WHERE
              department = t1.department
        ) AS COUNT
      FROM
        (
          SELECT
              DISTINCT department
            FROM students
        ) t1

P.185 リスト9.2

    SELECT price
        FROM price_list
        WHERE item = '懸垂マシン'
            AND NOW() BETWEEN start_date AND end_date
            OR (start_date >= NOW() AND end_date IS NULL)
    SELECT price
        FROM price_list
        WHERE item = '懸垂マシン'
            AND (NOW() BETWEEN start_date AND end_date
            OR (start_date <= NOW() AND end_date IS NULL))

P.193 図9.6内price_list最下行のprice_id

5
6

P.194 図9.7

active
flag

P.239 図11.2内(Viewに対応する下から2行目のrowid)

1
2

P.239 図11.2内(Viewに対応する一番下のrowid)

2
3

P.271 下から3行目

このような特徴を持つデータとして、たとえば,、
このような特徴を持つデータとして、たとえば

P.278 下から8行目

前回集計結果を更新した移行に
前回集計結果を更新した以降

P.338 図14.6

残高Yを読み取り 1,000,000円
残高Yを読み取り 1,100,000円

P.342 図14.8内の左下

1,000,000 - 100,000 = 900,000円
1,000,000 + 100,000 = 1,100,000円

P.352 上から4行目

そしてこれからも使うべきものなのについても
そしてこれからも使うべきものなのについても

商品一覧