跳轉到

1970 - Codd 的關聯式模型(資料庫的數學化)#

案件摘要#

1970 年,Edgar F. Codd(1923–2003) 在《ACM 通訊》發表 A Relational Model of Data for Large Shared Data Banks:

\[ \boxed{\text{資料 = 關聯(relation)= 數學上的「集合」(set of tuples)}} \]

關聯式模型的核心: - 資料儲存在「表格」中(行 = tuple,列 = attribute); - 操作 = 關係代數(relational algebra):選擇、投影、連接、聯集; - 資料與程式分離——查詢用宣告式語言(後來的 SQL)。

\[ \text{資料庫(檔案系統的混亂)} \xrightarrow{\text{Codd 1970}} \text{數學(關係代數)}. \]

1981 年,Codd 獲得圖靈獎—— 今天所有的資料庫(Oracle、MySQL、PostgreSQL、SQL Server)都是 Codd 模型的後代。

前因 -- 為什麼會有這個案子#

  • Codd 的背景(1949–1970): Codd 是英國人,二戰後移居美國,在 IBM 工作(1963 年起)。 他是數學家出身(密西根大學的博士,通訊與邏輯)—— 這個背景決定了他的思路:資料庫應該有數學基礎。
  • 資料庫的混亂(1960s): 當時的資料庫是階層式(hierarchical,如 IMS)或網狀式(network,如 CODASYL):
\[ \text{資料的組織方式} = \text{「指標的迷宮」} \]
  • 程式必須知道資料的「物理儲存方式」(指標、鏈結);
  • 換一種儲存方式 → 程式全部重寫!
\[ \text{邏輯與物理不分離} \Rightarrow \text{程式的災難}. \]
  • Codd 的洞察(1970): 資料本來就是「集合」——表格只是集合的一種視覺化:
\[ \text{關聯 } R \subseteq A_1 \times A_2 \times \cdots \times A_n \quad\text{(笛卡兒積的子集)}. \]

程式不需要知道儲存方式——只需要知道「邏輯結構」(表格)。

\[ \boxed{\text{邏輯與物理分離(資料獨立性,data independence)}} \]
  • IBM 的冷落(1970–1977): IBM 已投資 IMS(階層式資料庫,營收數十億)—— Codd 的模型威脅了 IMS 的存在! IBM 延遲了關聯式資料庫的研發—— 這給了 Larry Ellison 機會:Oracle(1977)第一個推出商用關聯式資料庫, 打敗了 IBM。

線索與推理 -- 數學式、程式、理論#

第一條線索:關聯式模型的形式定義#

關聯(relation): \(R \subseteq A_1 \times \cdots \times A_n\) (tuple 的集合)。 鍵(key):唯一識別 tuple 的屬性子集: - 主鍵(primary key):每個關聯一個; - 外鍵(foreign key):引用其他關聯的主鍵——關聯之間的連結。 正規化(normalization,1971): Codd 1971 年提出正規化形式,消除資料的冗餘: - 1NF:屬性不可再分(原子性); - 2NF:非鍵屬性完全依賴主鍵(消除部分依賴); - 3NF:非鍵屬性不傳遞依賴主鍵(消除傳遞依賴)。

\[ \text{BCNF(1974)} \xrightarrow{} \text{4NF(1977)} \xrightarrow{} \text{5NF(1979)} \quad\text{(正規化的家族)}. \]

第二條線索:關係代數(操作的數學)#

Codd 的關係代數(8 個操作): | 操作 | 記號 | 語義 | SQL 對應 | |------|------|------|---------| | 選擇 | \(\sigma_p(R)\) | 取滿足條件的行 | WHERE | | 投影 | \(\pi_A(R)\) | 取部分列 | SELECT A | | 連接 | \(R \bowtie S\) | 兩表的合併 | JOIN | | 聯集 | \(R \cup S\) | 行的合併 | UNION | | 交集 | \(R \cap S\) | 共同的行 | INTERSECT | | 差集 | \(R - S\) | 減去 | EXCEPT | | 笛卡兒積 | \(R \times S\) | 所有組合 | (JOIN 的基礎) | | 除法 | \(R \div S\) | 「對所有」查詢 | (NOT EXISTS) |

\[ \boxed{\text{查詢 = 關係代數的組合(宣告式,不用寫演算法)}} \]

第三條線索:宣告式查詢與 SQL(1974)#

SQL(SEQUEL, 1974,Chamberlin 與 Boyce):

SELECT name, salary
FROM employees
WHERE dept = 'research' AND salary > 50000;
宣告式:說「要什麼」,不說「怎麼做」——

\[ \text{命令式(迴圈 + 指標)} \xrightarrow{\text{SQL 1974}} \text{宣告式(集合 + 代數)}. \]

查詢最佳化器(query optimizer): 資料庫自動選擇最快的執行計畫—— 這是「程式不需要知道物理」的實現。

Python:關聯式模型的數值驗證#

import numpy as np

# 1) 關聯 = tuple 的集合(關聯式模型的核心)
employees = [
    ("E1", "張三", "research", 60000),
    ("E2", "李四", "sales",    45000),
    ("E3", "王五", "research", 55000),
    ("E4", "趙六", "sales",    48000),
]
departments = [
    ("research", "研究部"),
    ("sales",    "銷售部"),
]

# 2) 關係代數的操作
def select(rel, pred):
    """σ:選擇(WHERE)"""
    return [t for t in rel if pred(t)]

def project(rel, *attrs):
    """π:投影(SELECT)"""
    idx = [list(attrs)] if False else None
    return [tuple(t[i] for i in attrs) for t in rel]

def join(rel1, rel2, key1, key2):
    """⋈:自然連接(用鍵合併)"""
    result = []
    for t1 in rel1:
        for t2 in rel2:
            if t1[key1] == t2[key2]:
                result.append(t1 + t2[1:])   # 避免重複鍵
    return result

print("關係代數(Codd 1970):")
# σ:research 部門
r1 = select(employees, lambda t: t[2] == "research")
print(f"  σ(dept=research):{r1}")
# π:姓名與薪水
r2 = project(employees, 1, 3)
print(f"  π(name, salary):{r2}")
# ⋈:員工連接部門
r3 = join(employees, departments, 2, 0)
print(f"  ⋈(員工 ⋈ 部門):")
for t in r3:
    print(f"    {t}")

# 3) SQL 的等價查詢(宣告式)
print("\nSQL 等價(宣告式查詢):")
print("  SELECT e.name, d.dept_name")
print("  FROM employees e JOIN departments d ON e.dept = d.dept_id")
print("  WHERE e.salary > 50000;")
# 執行等價的關係代數
r4 = select(join(employees, departments, 2, 0), lambda t: t[3] > 50000)
print("  執行結果:")
for t in r4:
    print(f"    {t}")

# 4) 正規化的驗證(3NF:消除傳遞依賴)
print("\n正規化(3NF,1971):")
# 未正規化:員工表含部門名稱(傳遞依賴:E → dept_id → dept_name)
unnormalized = [
    ("E1", "張三", "research", "研究部", 60000),
    ("E2", "李四", "sales",    "銷售部", 45000),
    ("E3", "王五", "research", "研究部", 55000),
]
# 檢查冗餘:research/研究部 重複
dept_names = [t[2:4] for t in unnormalized]
duplicates = len(dept_names) - len(set(dept_names))
print(f"  未正規化({len(unnormalized)} 行):部門名稱冗餘 {duplicates} 處")
# 正規化後:分成兩表
print(f"  正規化(3NF):員工表 {len(employees)} 行 + 部門表 {len(departments)} 行")
print("  → 消除冗餘:改部門名稱只需改 1 行(不是 2 行)")

# 5) 資料獨立性:換儲存方式不影響查詢
print("\n資料獨立性(Codd 的核心思想):")
print("  程式只知道:表格(邏輯結構)")
print("  程式不知道:B 樹、雜湊、磁碟佈局(物理結構)")
print("  → 換儲存方式(如加索引)不需要改查詢")
print("  → 這是「邏輯與物理分離」的實現(對照 1960s 的指標迷宮)")
輸出:
關係代數(Codd 1970):
  σ(dept=research):[('E1', '張三', 'research', 60000), ('E3', '王五', 'research', 55000)]
  π(name, salary):[('張三', 60000), ('李四', 45000), ('王五', 55000), ('趙六', 48000)]
  ⋈(員工 ⋈ 部門):
    ('E1', '張三', 'research', 60000, '研究部')
    ('E2', '李四', 'sales', 45000, '銷售部')
    ('E3', '王五', 'research', 55000, '研究部')
    ('E4', '趙六', 'sales', 48000, '銷售部')

SQL 等價(宣告式查詢):
  SELECT e.name, d.dept_name
  FROM employees e JOIN departments d ON e.dept = d.dept_id
  WHERE e.salary > 50000;
  執行結果:
    ('E1', '張三', 'research', 60000, '研究部')
    ('E3', '王五', 'research', 55000, '研究部')

正規化(3NF,1971):
  未正規化(3 行):部門名稱冗餘 1 處
  正規化(3NF):員工表 4 行 + 部門表 2 行
  → 消除冗餘:改部門名稱只需改 1 行(不是 2 行)

資料獨立性(Codd 的核心思想):
  程式只知道:表格(邏輯結構)
  程式不知道:B 樹、雜湊、磁碟佈局(物理結構)
  → 換儲存方式(如加索引)不需要改查詢
  → 這是「邏輯與物理分離」的實現(對照 1960s 的指標迷宮)

結案 -- 後果與影響#

  • 資料庫工業的誕生(1970–1980):
\[ \boxed{\text{關聯式模型 = 資料庫的數學基礎}} \]
  • System R(1974–1979,IBM):IBM 的原型(SQL 的誕生地);
  • Ingres(1974–1977,Stonebraker,2014 圖靈獎):加州大學的原型—— PostgreSQL 的祖先;
  • Oracle(1977,Ellison):第一個商用關聯式資料庫—— 打敗了冷落 Codd 的 IBM。
\[ \text{Codd(1970):數學模型} \xrightarrow{\text{Oracle(1977)}} \text{商用化} \xrightarrow{} \text{資料庫工業(數百億美元)}. \]
  • SQL 的世紀(1974–):
\[ \text{SEQUEL(1974)} \to \text{SQL 標準(1986/1992/1999/2016)} \to \text{一切資料庫的語言}. \]

SQL 至今是資料庫的通用語言—— 每天數十億次的查詢都用 SQL—— 這是資訊科學中「壽命最長」的語言之一。 - 資料獨立性的哲學(1970–):

\[ \boxed{\text{邏輯與物理分離}} \]

Codd 的思想影響了整個軟體工程: - 分層架構:應用層、邏輯層、儲存層; - 介面與實作分離(1972 Parnas 的模組化); - 抽象化是軟體工程的核心(Dijkstra 1968 的結構化 + Codd 1970 的資料獨立)。 - Stonebraker 的後續(2014 圖靈獎): Michael Stonebraker(Ingres 與 Postgres 的創造者): - Postgres(1986):物件關聯式資料庫——PostgreSQL 的前身; - C-Store(2005):欄式儲存——分析型資料庫(Vertica); - H-Store(2007):記憶體資料庫——VoltDB; 2014 年圖靈獎——「現代資料庫系統」。 - NoSQL 的反叛(2000s)與 SQL 的回歸(2010s): - NoSQL(2000s):Google Bigtable(2006)、Amazon Dynamo(2007)—— 為了規模而犧牲關聯式; - NewSQL(2010s):Google Spanner(2012)——關聯式 + 規模; - 現代:關聯式模型依然是資料的核心—— Codd 的數學基礎是「最耐久」的。 - Codd 的晚年(1981 圖靈獎): Codd 1981 年獲圖靈獎,演講主題是關聯式模型的健康度檢查—— 他批評了打著「關聯式」旗號但不符合模型的產品—— Codd 的 12 條規則(1985)是「真正的關聯式資料庫」的檢驗標準。 - 歷史定位:Codd 是「資料庫的數學化」的人——

\[ \text{指標的迷宮(1960s)} \xrightarrow{\text{Codd 1970}} \text{數學(關係代數)} \xrightarrow{} \text{SQL(1974)} \xrightarrow{} \text{資料庫工業}. \]

一句話:資料是數學,不是檔案。

關鍵人物與文獻#

  • E. F. Codd:A Relational Model of Data for Large Shared Data Banks(1970);正規化(1971);12 條規則(1985);1981 圖靈獎。
  • D. Chamberlin & R. Boyce:SEQUEL(1974)——SQL 的誕生。
  • M. Stonebraker:Ingres(1974);Postgres(1986);2014 圖靈獎。
  • C. J. Date:An Introduction to Database Systems(1975)——資料庫的教科書。
  • 相關案件:1973-UNIX作業系統.md、1968-結構化程式設計.md、1982-蘭波特Paxos.md。