勉強日記

チラ裏

理論から学ぶデータベース実践入門 ch1 SQLとリレーショナルモデル

gihyo.jp


まとめ

  • SQLを使う以上、リレーショナルモデルから逃れることはできない
  • リレーショナルモデルのリレーションとSQLのテーブルとの間にはさまざまな相違がある
  • テーブルをリレーション(集合の一種)の性質に少しでも近づけることが重要

そもそもSQLって?

  • リレーショナルデータベースに問い合わせを行う言語
  • したがって、リレーショナルモデルがベースになっている

リレーショナルモデルを知らなくてもSQLは書ける?

  • そういう人は多い
  • が、新にスキルのあるDBエンジニアになるには必修

SQLとリレーショナルモデルって実はあんまり似てないよね?

RDBはリレーショナルモデルを正しく実践してこそ真価を発揮する!

  • SQLはリレーショナルモデルをベースとしている
  • ので、リレーショナルモデルに沿った演算が得意
  • しかし柔軟さゆえ、リレーショナルモデルから逸脱した使い方もできてしまう
    • いつの間にか非常に効率の悪いクエリばかり書くことに
    • SQL文が複雑怪奇に

リレーショナルモデル

  • データモデル
    • データをどのように表現するか
  • リレーショナルモデル
    • データモデルの一種
      • 他には、KVSとか
  • リレーション
    • リレーショナルモデルにおける最重要概念

リレーションの定義

  • ERD: Entity Relationship DiagramのRelationshipは関係ない
  • Relationに相当するのはテーブルそのもの
  • リレーションの構成要素
    • 見出し(Heading)
      • n個の属性の集合
      • 属性(Attribute)
        • 名前とデータ型とのペア
    • 本体(Body)
      • タプルの集合
      • タプル(tuple)
        • 属性値の集合
        • 属性値は見出しで定義されたものと一致すること
  • リレーショナルモデルとSQLにおける各オブジェクトの対応
    • ただし厳密に対応するものではない(後述)
リレーショナルモデル SQL
リレーション テーブル
タプル
属性 カラム

集合とリレーショナルモデル

  • リレーションは集合の一種
    • 集合の性質をもつ
  • 集合(Set)
    • ものの集まり
  • 要素、元(Element)
    • 集合に含まれる個々のもの
    • 満たすべき要件
      • 集合に含まれているかを不確定要素がなく判定できる
        • unknownはダメ
      • 重複してはいけない
        • 含まれているか、いないかのみ
        • 何個含まれているか、が演算結果に影響を及ぼしてはならない
      • それ以上分割できない
  • リレーショナルモデルとNULL
    • NULLはunknownを表すマーカーなので集合には含められない
    • よってリレーションにも含められない
  • 有限集合と無限集合
    • 異なる性質をもつもの
    • コンピュータで表現する以上、有限集合のみ考えれば良い

リレーションの演算

  • データと演算はセットになって初めて役に立つ
  • 演算
    • 制限(Restrict)
      • 特定の条件に合うタプルのみ含んだリレーションを返す
      • 元のリレーションの部分集合
    • 射影(Projection)
      • 特定の属性だけを含んだリレーションを返す
      • タプルに重複が生ずることがある
        • その場合、同一のタプルとみなされる
          • 集合だから「何個含まれるか」は演算結果に影響しない
    • 拡張(Extend)
      • 属性を増やす
        • たいていderivative
    • 属性名変更(Rename)
    • 和(Union)
      • 2つのリレーションに含まれるすべてのタプルで構成されるリレーションを返す
      • 重複は解消
    • 積/交わり(Intersect)
      • 2つのリレーションの共通部分になっているリレーションを返す
    • 差(Difference)
      • 2つのリレーションのうち一方のリレーションにのみ含まれるタプルから構成されるリレーションを返す
      • 交換則成り立たない
    • 直積(Product)
      • 2つのリレーションのタプルをそれぞれ組み合わせたリレーションを返す
      • 生成されたリレーションの見出しには2つのリレーションの見出しが持つ属性がすべて含まれる
    • 結合(Join)
      • 共通の属性を持つ2つのリレーションを、その共通の属性の値が同じタプル同士組み合わせたリレーションを返す
  • SQLの「外部結合」はリレーションの演算には含まれない
    • 結果にNULLを含む可能性があるため
  • 積、直積は結合の特殊なパターン
    • 積: 属性がすべて共通
    • 直積: 共通の属性が存在しない

コラム: 要素にNULLが含まれていると……

  • NULLはリレーショナルモデルを根底から覆す不穏因子
  • unknownが絡むため論理的に正しい答えは得られようもない

クロージャという性質

  • リレーションの演算は閉包
    • 数珠つなぎのように演算を記述できるため非常に重要
    • リレーショナルモデルの真骨頂

リレーショナルモデルにおけるデータ型

  • ドメインとも
  • とりうる値の集合
  • タプルが取りうる値は、属性のドメインの直積
  • リレーショナルモデルはなにもかも集合
    • リレーション
      • 見出し
      • 本体
        • タプル
          • 属性のデータ型

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

  • DMLとの対応関係

SELECTの基本形

  FROM テーブルのリスト  -- 直積
 WHERE 検索条件  -- 制限
SELECT カラムのリスト  -- 射影
;
  • RDBの中核たるSELECT文からして3つのリレーション演算からなる
  • 論理的には上記の順番
    • 実装上は最適化が行われ、変わるだろうが…
      • 行の直積集合全部をフェッチするわけはない
    • SELECT句の中で定義したエイリアス(拡張、属性名変更)をWHERE句で使えない理由

INSERT(挿入)

  • SQLにおけるテーブルは値と変数の両方の役割をもつ
  • リレーションは値である
    • 値そのものをmodifyするわけではない
a = a + 1;
  • Relvar(Relation Variable, 関係変数)
    • 値の入れ物
  • INSERT:Relvarに格納されたリレーションを新しいリレーションに置き換える操作
    • 新しいリレーション: 和集合
R := R ∪ {T}

DELETE(削除)

R := R - {T}
  • 差集合

UPDATE(更新)

R := (R - {T}) ∪ {T2}
  1. WHERE句の条件に適合するリレーション{T}との差集合をとり
  2. 修正を加えたリレーション{T2}との和集合をとる

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

  • SQLをリレーショナルモデルに沿って使うためには封印する必要がある

要素の重複

  • 制約がない場合、行が重複してもSQL上エラーにならない
  • ここにおいて、テーブルはそもそも集合(Set)でない
    • あえて言えばMultiset
    • SetとMultisetの性質は異なる
  • テーブルを集合と同じように使うには何らかの一意性制約が必要

要素間の順序

  • SQLには順序が存在する
    • カラム
      • カラム位置
      • ROWNUM関数、ORDER BY句

リレーションの更新

  • テーブルは値と変数の両方の機能を有し、mutable
  • リレーションは値であり、immutable

トランザクション

  • 値と変数の両方の機能を有する、SQLのテーブルならでは
    • cf. リレーションはそもそも更新できないためACID特性は一切関係ない
    • SQLだからこそ意味のある概念

ストアドプロシージャ

  • 集合演算を真っ向から否定する行為

NULL

  • Not Applicable / Unknown
  • 値ではないため集合に含めることはできない

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

  • 重要なのは、リレーショナルモデルの限界を知ること
    • リレーショナルモデルを適用できる部分と、そうでない部分とを見極めよ
    • 適用可能な部分ではしっかりと実践せよ
  • リレーショナルモデルの解釈自体を歪めるのはNG
      • NULLの許容
      • 属性やタプルに順序があるものと考える
    • 数学的な正しさから乖離する
  • 【所感】関数型プログラミングと似たものを感じる
    • 完全に副作用を排すると目の前の箱が熱くなるだけ
    • 純粋関数部分と副作用のある部分とを分けることが肝要