數(shù)據(jù)庫表格設(shè)計(jì)原則

數(shù)據(jù)三范式

總關(guān)系是依次遞進(jìn)

1. 第一范式(1NF)--確保原子性:

列的原子性,不能再拆分其他幾列

2. 第二范式(2NF)--確保表中每列都和主鍵相關(guān):

先滿足1NF,然后每張表要有主鍵,并且確保每一列都和主鍵相關(guān),而不是主鍵的一部分(主要針對聯(lián)合主鍵)。換言之,一個(gè)表中只保存一種數(shù)據(jù)而不是多種數(shù)據(jù)。
錯(cuò)誤示范中,訂單編號(hào)和商品編號(hào)作為聯(lián)合主鍵,但商品信息只跟商品編號(hào)有關(guān)。

商品訂單信息錯(cuò)誤設(shè)計(jì)

正確示范:
商品訂單信息正確設(shè)計(jì)

3. 第三范式(3NF)--確保每列都和主鍵直接相關(guān),而不是間接相關(guān)

第三范式需要確保數(shù)據(jù)表中的每一列數(shù)據(jù)都和主鍵直接相關(guān),而不能間接相關(guān)。不能傳遞依賴,如非主鍵列A依賴非主鍵列B,非主鍵列B依賴主鍵。
關(guān)鍵字段 → 非關(guān)鍵字段x → 非關(guān)鍵字段y

  1. 例子一:比如在設(shè)計(jì)一個(gè)訂單數(shù)據(jù)表的時(shí)候,可以將客戶編號(hào)作為一個(gè)外鍵和訂單表建立相應(yīng)的關(guān)系。而不可以在訂單表中添加關(guān)于客戶其它信息(比如姓名、所屬公司等)的字段。如下面這兩個(gè)表所示的設(shè)計(jì)就是一個(gè)滿足第三范式的數(shù)據(jù)庫表。
    訂單信息和客戶信息
  1. 例子二:假定學(xué)生關(guān)系表為Student(學(xué)號(hào), 姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話),關(guān)鍵字為單一關(guān)鍵字"學(xué)號(hào)",因?yàn)榇嬖谌缦聸Q定關(guān)系:

(學(xué)號(hào)) → (姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話)

這個(gè)數(shù)據(jù)庫是符合2NF的,但是不符合3NF,因?yàn)榇嬖谌缦聸Q定關(guān)系:

(學(xué)號(hào)) → (所在學(xué)院) → (學(xué)院地點(diǎn), 學(xué)院電話)

即存在非關(guān)鍵字段"學(xué)院地點(diǎn)"、"學(xué)院電話"對關(guān)鍵字段"學(xué)號(hào)"的傳遞函數(shù)依賴。
它也會(huì)存在數(shù)據(jù)冗余、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
把學(xué)生關(guān)系表分為如下兩個(gè)表:

學(xué)生:(學(xué)號(hào), 姓名, 年齡, 所在學(xué)院);
學(xué)院:(學(xué)院, 地點(diǎn), 電話)


范式化和反范式化的優(yōu)缺點(diǎn)

范式化的優(yōu)點(diǎn)

  1. 重復(fù)數(shù)據(jù)少,不冗余。
  2. 維護(hù)更新快。
  3. 范式化的表更小,可在內(nèi)存中運(yùn)行。

范式化的缺點(diǎn)

  1. 查詢的時(shí)候經(jīng)常需要很多的關(guān)聯(lián),增加查詢的代價(jià)。也可能使一些索引策略無效,因?yàn)榉妒交瘜⒘蟹旁诓煌谋碇?,而這些列在一個(gè)表中本可以屬于同一個(gè)索引。

反范式化的優(yōu)點(diǎn)

  1. 避免關(guān)聯(lián),幾乎所有數(shù)據(jù)可以在一張表中顯示。
  2. 可以設(shè)計(jì)有效的索引。

反范式化的缺點(diǎn)

  1. 冗余數(shù)據(jù)多,更新維護(hù)麻煩,刪除數(shù)據(jù)時(shí)也容易丟失重要信息。

一些建議

1. 適度冗余,減少join的關(guān)聯(lián)

冗余更新頻率不高,但是查詢頻率極高的字段。如訂單中的商品名稱,微博發(fā)帖中的用戶昵稱。

2. 大字段垂直拆分。

大字段拆分

如把博客列表中的內(nèi)容拆分出去,訪問列表的時(shí)候不讀取博客內(nèi)容,為縱深的邏輯關(guān)系。

3. 大表水平拆分

舉例說明:在一個(gè)論壇系統(tǒng)里,管理員經(jīng)常會(huì)發(fā)一些帖子,這些帖子要求在每個(gè)分類列表里都要置頂。
設(shè)計(jì)方案一:在發(fā)帖表里增加一列用來標(biāo)示是否是管理員發(fā)帖,這樣在每個(gè)分類列表展示時(shí)就需要對發(fā)帖表查詢兩次,一次是置頂帖,一次是普通帖,然后將兩次結(jié)果合并。如果發(fā)帖表內(nèi)容較大時(shí),查詢置頂帖的性能開銷會(huì)比較大。
設(shè)計(jì)方案二:將置頂帖存放在一個(gè)單獨(dú)的置頂表里。因?yàn)橹庙斕麛?shù)量相比會(huì)很少,但訪問頻率很高,這樣從發(fā)帖表里分拆開來,訪問的性能開銷會(huì)少很多。

4. 合適的數(shù)據(jù)類型

如果數(shù)據(jù)量一樣,但數(shù)據(jù)類型更小的話,數(shù)據(jù)存放同樣的數(shù)據(jù)就會(huì)占用更少的空間,這樣檢索同樣的數(shù)據(jù)所帶來的IO消耗自然會(huì)降低,性能也就很自然的得到提升。此外,mysql對不同類型的數(shù)據(jù),處理方式也不一樣,比如在運(yùn)算或者排序操作中,越簡單的數(shù)據(jù)類型操作性能越高,所以對于要頻繁進(jìn)行運(yùn)算或者排序的字段盡量選擇簡單的數(shù)據(jù)類型。


合適的數(shù)據(jù)類型

參考

  1. 阿里巴巴Java開發(fā)手冊
  2. MySQL表設(shè)計(jì)原則
  3. 數(shù)據(jù)庫三范式詳解+例子
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容