這篇文章進入資料庫系列文章的重要主題——架構設計。
架構設計在做什麼?簡單來說,就是在規劃你的表單要有哪些欄位、表單之間要怎麼關聯。而設計架構時,有一個最重要的核心精神:
避免資料重複。
為什麼資料重複這麼嚴重?讓我們從工程師常講的一個原則開始說起。
工程師的 DRY 原則
工程師有一個原則叫 DRY,全名是 Don’t Repeat Yourself(不要重複你自己)。
當你複製貼上,等於是把同樣的東西「各自獨立」地放在好幾個地方。這些地方之間沒有任何連結,改了其中一個,其他的不會跟著變。
所以之後如果要改,你必須:
- 記得你複製過哪些地方
- 每一個地方都找出來改掉
問題是,大多數人複製貼上之後就忘了。結果有些地方改到,有些地方沒改到,程式就壞了。
資料庫重複資料的三大問題
程式碼重複已經很麻煩了,資料庫的重複問題更可怕。
Update 要改很多次
假設你的表單設計不好,客戶的地址被存在三個不同的地方:
- 「客戶」表單裡有一個地址欄位
- 「訂單」表單裡也存了一份送貨地址
- 「發票」表單裡又存了一份帳單地址
有一天客戶搬家了,你更新(update)了「客戶」表單的地址,但忘了更新「訂單」和「發票」表單。
結果:
- 「客戶」表單顯示新地址
- 「訂單」表單顯示舊地址
- 「發票」表單也顯示舊地址
- 到底哪個才是對的?
這就是「資料不一致」。
Delete 要刪很多次
同樣的道理,如果你要刪除某筆資料,但它重複存在很多地方,你也必須全部都刪到。
漏刪任何一個地方,就會留下「孤兒資料」,造成系統混亂。
你不知道哪裡需要同步修改
最麻煩的是,很多時候你根本不知道或不記得哪些地方有重複的資料。
這不是粗心的問題,而是系統設計的問題。如果架構本身就允許重複,遲早會出事。
銀行資料不一致的風險
想像這件事發生在銀行:
你的帳戶餘額因為系統設計不良,被存在多個地方:
- A 系統說你有 10,000 元
- B 系統說你有 8,000 元
到底哪個是真的?
這種情況不只是「不方便」,而是可能造成金錢損失、客戶糾紛、甚至法律問題。
這就是為什麼我們要嚴格避免重複。
程式碼如何避免重複?
在程式設計中,如果發現某段資料或運算重複出現很多次,我們會怎麼做?
把它設成變數或函數,然後在別的地方「引用」它。
什麼是「引用」?就是不要把資料本身複製過去,而是指向那個資料存放的地方。
舉個例子,假設你有一個變數存著公司地址:
公司地址 = "台北市信義區松仁路 100 號"當你需要在不同地方用到這個地址時,你不會把整串地址複製貼上,而是直接寫「公司地址」這個變數名稱。這樣所有用到「公司地址」的地方,其實都是指向同一個來源。
好處是什麼?
- 地址只存在一個地方
- 所有引用它的地方都會自動拿到同樣的內容
- 要改的時候,只需要改那一個地方,其他地方就自動更新了
這個「引用」的概念,在資料庫裡面也有對應的做法——就是「關聯」。
資料庫如何避免重複?
資料庫的解法跟程式碼一樣:讓每筆資料只存在一個地方,需要的時候用「關聯」去指向它。
這就是「架構設計」要做的事。
什麼是資料庫架構?
簡單來說,資料庫架構就是在描述:
- 你有哪些表單
- 每個表單裡有哪些欄位
- 這些表單之間怎麼互相關聯
表單之間的關聯是什麼意思?
假設你有一個「訂單」表單和一個「客戶」表單。每一筆訂單都會對應到某一個客戶,所以「訂單」表單裡面會有一個欄位,專門用來指向「客戶」表單的某一筆資料。
這種「A 表單的某個欄位指向 B 表單」的設計,就是表單之間的關聯。
訂單表單透過「客戶 ID」欄位,指向客戶表單的某一筆資料
為什麼用關聯可以避免重複?
假設你把客戶的地址直接寫在每一筆訂單裡,那同一個客戶下了 10 筆訂單,地址就會重複 10 次。
但如果你用關聯的方式,訂單只存「客戶 ID」,地址只存在客戶表單那一個地方。這樣不管客戶下了幾筆訂單,地址永遠只有一份,要改也只要改一個地方。
怎麼判斷哪些欄位該放一起?
現在我們知道:好的架構設計要避免重複,方法是把資料集中存在一個地方,其他地方用「關聯」去指向它。
但實際在設計的時候,你會遇到一個問題:
怎麼判斷哪些欄位該放在同一個表單?哪些該分開?
例如:「客戶姓名」和「客戶地址」應該放在一起嗎?「訂單日期」和「送貨地址」呢?「商品名稱」和「商品價格」呢?
這些問題沒有標準答案,要看你怎麼分析資料之間的關係。
之前的文章教過一種方法,就是用「個體、性質、關係」來思考。
用個體、性質、關係來設計資料庫
這個方法是這樣的:
- 先找出有哪些個體(例如:客戶、商品、訂單)
- 這些個體有哪些性質(例如:客戶有姓名、電話)
- 個體之間有什麼關係(例如:客戶「購買」商品)
這個方法在簡單的情境下很好用,但當世界變複雜,問題就來了。
周年慶案例:商品是個體還是關係?
之前課堂上看過一個周年慶的案例。
一開始我們直覺認為「商品」是一個個體——它就是一個東西嘛,應該獨立存在。
但仔細分析後發現,「商品」其實是消費者和店家之間的關係。因為同一個東西,在不同的情境下(例如不同的促銷活動),它的價格、組合方式都可能不同。
這個例子告訴我們:現實世界比想像中複雜,光靠「個體、性質、關係」的直覺判斷,有時候會出錯。
用欄位相依關係來設計架構
既然直覺判斷不夠可靠,這堂課會換一個角度:
觀察欄位之間的「相依關係」,來決定哪些欄位該放在一起、哪些該分開。
後續的文章會介紹很多具體的原則(這些都是前人留下來的經驗法則),幫助我們:
- 看出欄位之間的關係
- 把欄位切分到正確的表單
- 避免資料重複
資料庫架構設計重點整理
這篇文章介紹了資料庫架構設計的核心精神:
- DRY 原則:不要重複,因為重複會讓修改和刪除變得困難
- 資料不一致是重複造成的最大風險,嚴重時會有金錢或法律問題
- 程式碼的解法是用變數和函數來引用,資料庫的解法是用關聯來指向
- 架構設計就是規劃表單的欄位,以及表單之間的關聯,讓每筆資料只存在一個地方
- 之前用「個體、性質、關係」來思考,但複雜情境下容易判斷錯誤(例如周年慶的商品案例)
- 接下來會用「欄位之間的相依關係」來設計架構
接下來的文章會介紹具體的設計原則,幫助我們判斷欄位該怎麼切分,達成「不重複」的目標。