資料庫設計之冗餘欄位設計
在設計資料庫時,某一欄位屬於一個表,但它又同時出現在另一個或多個表,且完全等同於它在其本來所屬表的意義表示,那麼這個欄位就是一個冗餘欄位。
——以上是我自己給出的定義
冗餘欄位的存在到底是好還是壞呢(
冗餘是為了效率,減少join。單表查詢比關聯查詢速度要快。
某個訪問頻繁的欄位可以冗餘存放在兩張表裡,不用關聯了。
)?這是一個不好說的問題。可能在有人看來,這是一個很蹩腳的資料庫設計。因為在資料庫設計領域,有一個被大家奉為圭臬的資料庫設計正規化,這個正規化理論上要求資料庫設計邏輯清晰、關係明確,比如,”使用者暱稱”欄位”nickname”本來屬於表”user”,那麼,表示”使用者暱稱”的欄位就唯一的只應該屬於”user”表的”nickname”欄位,這樣,當用戶要修改暱稱的時候,程式就只需要修改 user.nickname這個欄位就行了,瞧,很方便。不過問題也隨之而來,我在其他資料表(如訂單orders表)裡只儲存了使用者的ID,我要通過這個ID值得到使用者暱稱該怎麼辦呢?一個普遍的解決方法是通過聯接(join),在查詢時,通過id這個唯一條件聯接兩個表,從而取到使用者的暱稱。
這樣確實是沒問題,我也一直覺得這樣是最好的方案,擴充套件方便,當要更新使用者資訊時,程式中要修改的地方很少,但是隨著資料庫裡資料不斷增加,百萬,千萬,同時,使用者表的資料肯定也在不斷的增加的,它可能是十萬,百萬。這個時候,你會發現兩個表通過聯接來取資料就顯得相當費力了,可能你只需要取一個nickname這個使用者暱稱屬性,你就不得不去聯一下那個已經幾十萬的使用者表進行檢索,其速度可想而知了。
這個時候,你可以嘗試把nickname這個欄位加到orders這個訂單表中,這樣做的好事是,當你要通過訂單表呈現一個訂單列表時,涉及使用者的部分可能就不需要再進行聯接查詢了(變成了單表查詢)。當然,有利就有弊,這樣做的弊端就是,當你嘗試更新使用者資訊時,你必須記得使用者資訊表裡當前被更新的欄位中,有哪些是冗餘欄位,分別屬於哪些表,找到他們,然後加入到你的更新程式段中來。這個是程式中的開銷,開銷在開發人員的時間上了。至於這樣做是否值得,就得看具體情況而定了。
所以,目前要建立一個關係型資料庫設計,我們有兩種選擇:
- 儘量遵循正規化理論的規約,儘可能少的冗餘欄位,讓資料庫設計看起來精緻、優雅、讓人心醉。
- 合理的加入冗餘欄位這個潤滑劑,減少join,讓資料庫執行效能更高更快。
選擇哪一種呢?如果你是一個美學狂人,並且財大氣粗,非要使用第一種方案,也沒關係,這種方案的短板並非不可救藥的。比如,你可以增加伺服器,從資料庫叢集入手,進行讀寫分離,讀的時候可以將壓力分散到不同的資料庫伺服器上,這樣也可以獲得很好的效能,只是多付出了硬體成本和維護成本。或者,你可以在資料庫前端架設Memcached之類的快取服務,減少讀寫資料庫的次數,也可以達到同樣的效果。問題在於你確定你需要快取之類的東西。
——以上是我自己給出的定義
冗餘欄位的存在到底是好還是壞呢(
冗餘是為了效率,減少join。單表查詢比關聯查詢速度要快。
某個訪問頻繁的欄位可以冗餘存放在兩張表裡,不用關聯了。
)?這是一個不好說的問題。可能在有人看來,這是一個很蹩腳的資料庫設計。因為在資料庫設計領域,有一個被大家奉為圭臬的資料庫設計正規化,這個正規化理論上要求資料庫設計邏輯清晰、關係明確,比如,”使用者暱稱”欄位”nickname”本來屬於表”user”,那麼,表示”使用者暱稱”的欄位就唯一的只應該屬於”user”表的”nickname”欄位,這樣,當用戶要修改暱稱的時候,程式就只需要修改 user.nickname這個欄位就行了,瞧,很方便。不過問題也隨之而來,我在其他資料表(如訂單orders表)裡只儲存了使用者的ID,我要通過這個ID值得到使用者暱稱該怎麼辦呢?一個普遍的解決方法是通過聯接(join),在查詢時,通過id這個唯一條件聯接兩個表,從而取到使用者的暱稱。
這樣確實是沒問題,我也一直覺得這樣是最好的方案,擴充套件方便,當要更新使用者資訊時,程式中要修改的地方很少,但是隨著資料庫裡資料不斷增加,百萬,千萬,同時,使用者表的資料肯定也在不斷的增加的,它可能是十萬,百萬。這個時候,你會發現兩個表通過聯接來取資料就顯得相當費力了,可能你只需要取一個nickname這個使用者暱稱屬性,你就不得不去聯一下那個已經幾十萬的使用者表進行檢索,其速度可想而知了。
這個時候,你可以嘗試把nickname這個欄位加到orders這個訂單表中,這樣做的好事是,當你要通過訂單表呈現一個訂單列表時,涉及使用者的部分可能就不需要再進行聯接查詢了(變成了單表查詢)。當然,有利就有弊,這樣做的弊端就是,當你嘗試更新使用者資訊時,你必須記得使用者資訊表裡當前被更新的欄位中,有哪些是冗餘欄位,分別屬於哪些表,找到他們,然後加入到你的更新程式段中來。這個是程式中的開銷,開銷在開發人員的時間上了。至於這樣做是否值得,就得看具體情況而定了。
所以,目前要建立一個關係型資料庫設計,我們有兩種選擇:
- 儘量遵循正規化理論的規約,儘可能少的冗餘欄位,讓資料庫設計看起來精緻、優雅、讓人心醉。
- 合理的加入冗餘欄位這個潤滑劑,減少join,讓資料庫執行效能更高更快。
選擇哪一種呢?如果你是一個美學狂人,並且財大氣粗,非要使用第一種方案,也沒關係,這種方案的短板並非不可救藥的。比如,你可以增加伺服器,從資料庫叢集入手,進行讀寫分離,讀的時候可以將壓力分散到不同的資料庫伺服器上,這樣也可以獲得很好的效能,只是多付出了硬體成本和維護成本。或者,你可以在資料庫前端架設Memcached之類的快取服務,減少讀寫資料庫的次數,也可以達到同樣的效果。問題在於你確定你需要快取之類的東西。