歡迎來到關聯式資料庫的世界!
資料庫是現今幾乎所有商業活動的骨幹,從你最愛的串流影音服務到學校的教務系統,無一例外。本章將帶你深入了解關聯式資料庫(Relational Databases),其核心在於如何高效且合乎邏輯地組織數據,讓電腦能夠快速且可靠地檢索資訊。
別擔心「正規化(normalisation)」這類名詞聽起來很複雜,我們會透過簡單的類比將其拆解。學完本章後,你將能理解數據模型是如何構建的、資料表之間如何連結,以及如何使用 SQL 這種強大的語言與資料庫溝通。準備好成為數據架構師了嗎?我們出發吧!
1. 概念數據模型與實體關聯模型 (Entity Relationship Modelling)
什麼是實體 (Entity)?
實體 (Entity) 就是我們想要儲存數據的現實世界對象或概念。你可以把它想像成資料庫結構中的一個「核心名詞」。
範例:客戶 (CUSTOMER)、產品 (PRODUCT)、訂單 (ORDER)、課程 (COURSE)。
屬性 (Attributes / Fields)
屬性 (Attributes) 是實體的特徵或性質。這些就是你實際要儲存的資訊碎片。
在實作的資料庫(真實的軟體)中,屬性被稱為欄位 (fields) 或資料行 (columns)。
範例:學生 (STUDENT) 實體可能擁有諸如:學號 (StudentID)、姓名 (Name)、出生日期 (DateOfBirth) 等屬性。
實體識別碼 (Entity Identifier / Primary Key)
實體識別碼 (Entity Identifier) 或稱主鍵 (Primary Key, PK),是一個或多個屬性的組合,用來唯一識別實體(資料表)中的每一筆記錄(資料列)。
在數據建模中,我們透過底線來標示實體識別碼。
範例:完整的實體描述寫作:
STUDENT(StudentID, Name, DateOfBirth)
有時,唯一識別碼必須由多個屬性結合而成。這稱為複合實體識別碼 (Composite Entity Identifier) 或複合主鍵 (Composite Primary Key)。
範例:如果班級名單沒有使用學號,你可能會使用 (FirstName, LastName, DateOfBirth) 來唯一識別一個人。
關係程度 (Degrees of Relationship)
關係定義了實體之間如何互動。關係程度 (Degree of relationship) 告訴我們一個實體的多少個實例,可以與另一個實體的多少個實例相關聯。
在實體關聯圖 (ERD) 中,這些通常以特定的符號表示:
一對多 (One-to-Many, 1:M)
實體 A 的一個實例可以與實體 B 的零個、一個或多個實例相關聯;但實體 B 的一個實例僅能與實體 A 的一個實例相關聯。
類比:一位部門主管 (HEAD OF DEPARTMENT) 管理許多教師 (MANY TEACHERS)。
符號範例:HEAD_OF_DEPT --< TEACHER
多對一 (Many-to-One, M:1)
這是一對多的反向關係。
類比:許多教師 (MANY TEACHERS) 向一位部門主管 (ONE HEAD OF DEPARTMENT) 匯報。
符號範例:TEACHER >-- HEAD_OF_DEPT
一對一 (One-to-One, 1:1)
實體 A 的一個實例正好與實體 B 的一個實例相關聯,反之亦然。
類比:一個人 (PERSON) 持有一本護照 (PASSPORT)。一本護照屬於一個人。
符號範例:PERSON ---- PASSPORT
多對多 (Many-to-Many, M:M)
實體 A 的一個實例可以與實體 B 的許多實例相關聯,實體 B 的一個實例也可以與實體 A 的許多實例相關聯。
注意:在實際的關聯式資料庫設計中,M:M 關係必須被拆解為兩個 1:M 關係(通常會使用一個連結表 junction table),但在概念模型中,你必須熟悉這種關係。
類比:一位學生 (STUDENT) 註冊許多課程 (MANY COURSES)。一門課程 (COURSE) 由許多學生 (MANY STUDENTS) 修讀。
符號範例:STUDENT >--< COURSE
2. 關聯式資料庫的核心概念
關聯式資料庫的概念
關聯式資料庫 (Relational Database) 是結構化數據項的集合,組織成一組經過正式定義的資料表(關聯,relations)。我們無需重新組織資料庫本身的資料表,就能以多種不同的方式存取或重新組裝數據。
其核心理念在於數據被儲存在分離的資料表(關聯)中,並透過稱為外鍵 (Foreign Keys) 的特殊屬性連結在一起。
連結抽象術語與實作術語
在討論抽象數據模型時,我們會使用特定的術語。當討論實際運作的資料庫時,我們會使用不同(但等價)的術語:
- 關聯/資料表 (Relation/Table): 儲存數據的資料庫表格。
- 屬性/欄位 (Attribute/Field): 資料表中的欄位標題。
- 實體識別碼/主鍵 (Entity Identifier/Primary Key, PK): 用來唯一識別資料列的欄位。
外鍵 (Foreign Key, FK)
外鍵 (Foreign Key) 是某個資料表中的一個屬性,它指向另一個資料表的主鍵。這是建立資料表之間連結的關鍵要素。
記憶口訣:外鍵之所以叫「外」鍵,是因為它屬於另一個資料表,但在這裡被用來連結回該源頭。
範例:如果 TEACHER 表格中有一個 DeptID(外鍵),這個 DeptID 必須對應到 DEPARTMENT 表格中現有的 DeptID(主鍵)。
3. 資料庫設計與正規化技術
為什麼要正規化?
正規化 (Normalisation) 是設計資料庫結構的過程,旨在減少數據冗餘 (data redundancy)(重複儲存相同數據)並提高數據完整性 (data integrity)(確保數據準確且一致)。
如果不進行正規化,你將面臨以下風險:
- 更新異常 (Update Anomalies): 必須在多個地方更新同一條資訊。(如果課程名稱更改,你必須更新所有學生紀錄)。
- 插入異常 (Insertion Anomalies): 若沒有主鍵數據,就無法新增新數據。
- 刪除異常 (Deletion Anomalies): 刪除一項數據時,導致其他不相關的數據也一併遺失。
第三正規化 (Third Normal Form, 3NF)
課程大綱要求你理解第三正規化 (3NF) 以及為何資料庫需要正規化。你不需要去區分第一、第二與第三正規化之間的細節差異。
一個關聯(資料表)若滿足特定屬性,則稱為處於 3NF。其中最重要的是消除傳遞相依性 (Transitive Dependencies)。
3NF 的核心屬性:
在處於 3NF 的關聯中,每一個非鍵屬性都必須只相依於完整的主鍵。 本質上,不應該有任何非鍵欄位相依於另一個非鍵欄位。
不符合 3NF 的問題範例:
一個表格 ORDER(OrderID, CustomerID, CustomerName, ItemPrice)。
在這裡,CustomerName 相依於 CustomerID,而非直接相依於 OrderID(主鍵)。如果 CustomerID 的客戶更改了姓名,你就必須為他們下過的所有訂單更新此資訊。解決方法是將其拆分為兩個表格:ORDER 與 CUSTOMER。
達成 3NF 後,我們能確保資料庫穩定、靈活且更新效率高。
4. 結構化查詢語言 (SQL)
SQL 是用於與關聯式資料庫互動的標準語言。它允許你定義數據結構 (DDL) 並操作數據 (DML)。
資料定義語言 (DDL):定義資料表
你必須知道如何使用 SQL 定義資料庫資料表,並指定鍵與數據類型。
需掌握的關鍵數據類型:
- Integer (整數) 與 Real/Float (浮點數)。
- String (字串/文字) 與 Boolean (布林值,True/False)。
- Date/Time (日期/時間) 值。
建立資料表的範例:
CREATE TABLE Products (
ProductID INTEGER PRIMARY KEY,
Name STRING,
Price REAL
);
你也需要知道如何使用單一欄位新增外鍵約束 (Foreign Key constraint):
CREATE TABLE Orders (
OrderID INTEGER PRIMARY KEY,
CustomerID INTEGER,
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);
資料操作語言 (DML):管理數據
你必須熟悉以下基本的 SQL 指令:
1. 檢索數據 (SELECT)
用於從資料庫讀取數據。
- SELECT [屬性] FROM [資料表] WHERE [條件] ORDER BY [屬性]
- 範例:
SELECT Name, Price FROM Products WHERE Price > 100.00 ORDER BY Price DESC;
2. 插入數據 (INSERT)
用於新增記錄(資料列)。
- INSERT INTO [資料表] VALUES (值1, 值2, ...);
- 範例:
INSERT INTO Products VALUES (101, 'Laptop', 1200.00);
3. 更新數據 (UPDATE)
用於更改現有記錄。請務必使用 WHERE,否則你會更新每一筆記錄!
- UPDATE [資料表] SET [屬性] = [新值] WHERE [條件];
- 範例:
UPDATE Products SET Price = 1250.00 WHERE ProductID = 101;
4. 刪除數據 (DELETE)
用於移除記錄。同樣地,請務必使用 WHERE!
- DELETE FROM [資料表] WHERE [條件];
- 範例:
DELETE FROM Products WHERE ProductID = 101;
SQL 彙總函數 (Aggregate Functions)
這些函數會對一組資料列進行運算並傳回單一彙總值。你通常會搭配 GROUP BY 來將運算應用於數據子集。
- COUNT: 傳回符合特定條件的列數。
- SUM: 傳回數值欄位的總和。
- AVG: 計算數值欄位的平均值。
- MIN: 傳回欄位中的最小值。
- MAX: 傳回欄位中的最大值。
範例: SELECT COUNT(StudentID) FROM Students WHERE Course = 'CS';
使用 GROUP BY 的範例: SELECT Course, AVG(Score) FROM Results GROUP BY Course;
5. 客戶端-伺服器資料庫 (Client-Server Databases)
在多數大型系統中,資料庫託管於中央伺服器,由許多不同的使用者(客戶端)存取。這種架構稱為客戶端-伺服器資料庫系統 (Client Server Database System)。
並行存取 (Concurrent Access)
並行存取 (Concurrent Access) 意味著多個客戶端(使用者)可以同時嘗試存取與修改相同的數據。這對效率很有幫助,但引入了一個重大風險:遺失更新問題 (Lost Update Problem)。
遺失更新問題
當兩個或多個使用者幾乎在同一時間嘗試更新相同記錄,且更新過程互相干擾時,就會發生此問題。
逐步範例:
- 客戶端 A 讀取銀行帳戶餘額:$100。 \n
- 客戶端 B 讀取相同的銀行帳戶餘額:$100。
- 客戶端 A 計算存款 ($100 + $50 = $150) 並將 $150 寫回資料庫。
- 客戶端 B 計算提款 ($100 - $20 = $80) 並將 $80 寫回資料庫。
結果: 客戶端 A 的 $50 存款遺失了。最終餘額為 $80,但正確數值應為 $130。
記錄鎖定 (Record Locks)
為了維持數據的完整性 (integrity)(確保數據正確),必須透過記錄鎖定 (Record Locks) 來控制並行存取。
記錄鎖定可防止其他使用者在某人正在處理或更新記錄時存取或修改該記錄。
運作方式: 當客戶端 A 開始編輯銀行餘額時,系統會在該記錄上放置一個鎖。客戶端 B 必須等待客戶端 A 提交(儲存)變更並釋放鎖後,才能存取該記錄。
6. 大數據 (Big Data)
你知道嗎? 我們現在每兩天產生的數據量,比從文明曙光到 2003 年間累積的還要多!
大數據 (Big Data) 是一個通用術語,用來描述那些過於龐大或複雜,以至於無法使用傳統資料庫方法(如我們剛討論的關聯式資料庫)輕鬆儲存、處理或分析的數據集。
大數據的三個 V
大數據通常由三個主要特徵定義:
- 容量 (Volume): 數據量極大,無法單一伺服器容納,也無法由傳統工具處理。
- 速度 (Velocity): 數據往往以極快速度串流進來(例如股市價格、社交媒體動態),需要即時反應(毫秒至秒級)。
- 多樣性 (Variety): 數據以多種形式呈現(結構化、非結構化文字、影片、感測器讀數等)。這種缺乏統一結構的特性,使得關聯式表格不再適用。
分散式處理與函數式程式設計 (Functional Programming)
由於數據量過大,無法由單一伺服器處理,必須將任務分散至多部機器上處理 (distributed across multiple machines)。
函數式程式設計 (Functional Programming, FP) 語言(你之後可能會學到)常被用於處理大數據,因為它們非常適合編寫正確且高效的分散式代碼。這是因為 FP 依賴於:
- 不可變數據結構 (Immutable Data Structures): 數據建立後不可更改,防止伺服器之間的並行問題。
- 無狀態性 (Statelessness): 函數不依賴也不會改變外部狀態,因此可以輕鬆地在不同伺服器上獨立執行。
- 高階函數 (Map-Reduce): 像 Map-Reduce 這樣的技術(將函數對應到所有元素,然後將結果規約為單一值)被用來合併許多不同伺服器上的處理結果。
大數據的數據模型(非關聯式)
由於大數據通常缺乏嚴格的結構,因此需要非關聯式模型。
基於事實的模型 (Fact-Based Model)
在此模型中,每一條資訊都被捕捉為一個單一事實 (single fact)。
範例:與其建立一個包含 (姓名, 年齡, 地址) 的列,你儲存三個獨立的事實:(姓名: John), (年齡: 30), (地址: London)。
圖形架構 (Graph Schema: Nodes, Edges, Properties)
圖形資料庫用於表示複雜的關係(如社交網絡或推薦系統)。
- 節點 (Node/Entity): 代表一個獨立的實體(以橢圓形顯示)。
- 邊 (Edge/Relationship): 連接兩個節點的實線,上面標有描述關係的文字(例如「喜歡」、「是...的朋友」)。
- 屬性 (Properties/Attributes): 實體的特徵(顯示為連結到橢圓形的矩形)。
想像 Facebook:你是一個「節點」。你的城市是「屬性」。而「是朋友關係」就是連結你與另一個節點的「邊」。