當前位置:首頁(yè) > 設計 > 正文內容

一文讀懂數據庫設計的范式化|CDGA知識點(diǎn)補充

常德數碼快印4個(gè)月前 (07-08)設計6
印刷廠(chǎng)直印●彩頁(yè)1000張只需要69元●名片5元每盒-更多報價(jià)?聯(lián)系電話(huà):138-1621-1622(微信同號)

這個(gè)話(huà)題總是讓大家有點(diǎn)困惑。我的意思是如何記住每個(gè)規范化形式的作用?每次查找它時(shí),都會(huì )看到這些復雜的定義。所以我決定一勞永逸地解決這個(gè)問(wèn)題,并分享一種有用的理解方法。

在規范化數據庫中,數據以表格形式組織,這樣數據庫查詢(xún)或更新的結果始終清晰明確且符合預期。我們可以將規范化視為多層保證,每一層都確保查詢(xún)或更新數據時(shí)有一定的安全性。

什么是冗余

規范化可以消除冗余。它強制數據庫不被不必要地復制。例如:

假設我們想在上面的表格中存儲用戶(hù)的信息。您可能已經(jīng)注意到,同時(shí)存儲出生日期和年齡是不合邏輯的,因為年齡可以通過(guò)出生日期計算出來(lái)。這是冗余數據。如果我們犯了一個(gè)錯誤,輸入了錯誤的用戶(hù)出生日期值,那么他們的年齡列也需要更新。

但事實(shí)并非如此。假設印度決定將其國家代碼從 +91 更改為 +911,現在需要更新此表中的所有行。更好的方法是為每個(gè)表建立一個(gè)單獨的表來(lái)存儲國家代碼,并在獲取用戶(hù)信息時(shí)執行連接操作以獲取國家代碼。

第一范式(1NF)

列中的每個(gè)單元格僅包含一種類(lèi)型的值

大多數基于模式的數據庫甚至不允許這樣做。

單元格只能保存一個(gè)值

如果單個(gè)字段有多個(gè)值,最好將每個(gè)值表示在單獨的行中。

數據排序不應該傳達任何含義

除非另有說(shuō)明,否則查詢(xún)返回的數據的順序不應具有任何意義(如果我們在查詢(xún)中使用 ORDER BY 子句,那么返回數據的順序當然具有一定意義)。

這里,在第一個(gè)表中,我們期望以相同的方式返回結果以獲取存儲的信息(在本例中為高度)。對表的插入、更新和刪除操作也成為一項任務(wù)。我們必須重新排列現有值。單獨存儲高度為這些操作提供了靈活性,我們不必依賴(lài)存儲信息的順序。

不應有重復的組

假設我們正在創(chuàng )建一個(gè)游戲,需要創(chuàng )建一個(gè)表來(lái)存儲每個(gè)玩家的庫存。存儲這些值的一種方法如下。

但是,相同的數據會(huì )重復出現(物品名稱(chēng)、物品數量)。假設游戲中有 50 種不同的物品,我們就必須在表中添加 100 個(gè)不同的列,而對于那些物品不多的用戶(hù)來(lái)說(shuō),這會(huì )浪費空間。向游戲中添加更多物品也成為一項任務(wù),因為我們必須執行架構遷移,甚至可能進(jìn)行數據遷移。

我們可以按如下方式展平表格。

現在,添加新物品變得非常簡(jiǎn)單,只需在表中添加另一行,并且我們只會(huì )使用所需的空間。如果我們想知道玩家擁有的每個(gè)物品的數量,我們只需查詢(xún)包含該玩家 ID 的所有行,其余物品的數量為 0。

表中的每個(gè)條目都應該是唯一的

假設我們有一張存儲某人身高的簡(jiǎn)單表。從邏輯上講,同一個(gè)人有兩個(gè)條目是錯誤的。一個(gè)人的身高不能不同。每個(gè)表都需要一個(gè)主鍵。主鍵對于每行都是唯一的。它可以是單個(gè)列或列的組合。對于身高表,人的名字可以是主鍵。對于上例中的庫存表,(PlayerID, Item Name) 可以是主鍵。

第二范式(2NF)

讓我們重新審視庫存示例并存儲另一個(gè)值,即玩家評分。

該表遵循第一范式的所有規則。

它有一個(gè)主鍵(PlayerID,Item Name)

沒(méi)有重復的組

每列只存儲一種類(lèi)型的值

每個(gè)單元格僅存儲一個(gè)值

然而,我們遇到了一些問(wèn)題:

如果玩家丟失了所有物品,則無(wú)法存儲他們的評級,因為無(wú)法在表中輸入任何條目。當然,我們可以添加一個(gè)物品計數為 0 的行,但這更像是一種黑客行為。這被稱(chēng)為刪除異常。

如果玩家 1 的評級從首發(fā)變?yōu)橹屑?,?我們需要更新所有 3 行的評級。但如果在更新這些值的過(guò)程中出現系統問(wèn)題,玩家的評級就會(huì )不知何故同時(shí)是首發(fā)和中級。這被稱(chēng)為更新異常。

如果我們有新玩家,他們就是新手。但是,由于他們沒(méi)有物品,我們也無(wú)法存儲該玩家的評分。這是一個(gè)插入異常。

讓我們看看物品數量和玩家評級列。物品數量列取決于玩家 ID 和物品名稱(chēng)。因為數量是針對特定用戶(hù)庫存中的物品。但是,評級列僅取決于玩家 ID,與物品名稱(chēng)無(wú)關(guān)。

我們可以將這些函數依賴(lài)關(guān)系顯示為

{玩家 ID,物品名稱(chēng)} → {物品數量}

{玩家 ID} → {玩家評分}

這種符號表示左邊的每個(gè)值都與右邊的一個(gè)值相關(guān)聯(lián)。

確保表幾乎總是符合 2NF 的一個(gè)簡(jiǎn)單規則是確保每個(gè)非鍵屬性(不屬于主鍵的列)都依賴(lài)于整個(gè)主鍵,即不存在部分依賴(lài)關(guān)系。2NF 的實(shí)際定義比這更微妙。但是,這個(gè)定義在大多數情況下都有效。對于完整的定義,應該對所有候選鍵(而不僅僅是主鍵)遵循此部分依賴(lài)規則。

為了使我們的表符合 2NF,我們可以將部分依賴(lài)的列移到另一個(gè)表中。

注意:由于 2NF 形式取決于這樣一個(gè)事實(shí):如果非鍵屬性部分或完全依賴(lài)于鍵(如果鍵僅為單個(gè)列值),則 1NF 中的表將自動(dòng)變?yōu)?2NF。

第三范式(3NF)

讓我們再次查看我們在 2NF 部分中創(chuàng )建的 PlayerID、Rating 表。假設我們還想使用以下規則在此表中存儲玩家的技能等級:

技能等級 1–3,評級為入門(mén)級

技能等級 4–6,評級為中級

技能等級 7–9,評級為專(zhuān)家

該表現在如下所示:

此表符合 2NF,因為此表的主鍵是 PlayerID,并且評級和技能等級都取決于 playerID。但是,評級僅取決于通過(guò)玩家技能等級獲得的玩家 ID。評級取決于技能等級,技能等級取決于 playerID,即評級間接取決于 playerID。{PlayerID} → {Player Skill Level} → {Player Rating}如果玩家 1 將其技能等級從 3 升級到 4,則其評級需要從 Starter 更新為 Intermediate。如果在此更新過(guò)程中發(fā)生故障,則技能等級為 4 的玩家的評級可能為 Starter,這在邏輯上是不正確的。

這個(gè)問(wèn)題的解決方案是將傳遞依賴(lài)列分離到不同的表中。簡(jiǎn)而言之,每個(gè)非鍵屬性都應該只依賴(lài)于整個(gè)主鍵。

博伊斯-科德范式 (BCNF)

這是 3NF 的擴展。當表符合 3NF 時(shí),它不符合 BCNF 的情況非常少見(jiàn)。定義表明,對于每個(gè)函數依賴(lài)關(guān)系 A→B,A 應該是一個(gè)超級鍵(可以唯一標識一行的列組合)。

第四范式和第五范式

在大多數情況下,如果我們能夠按照第三范式 (3NF) 設計表,那么就可以避免不良關(guān)系設計中常見(jiàn)的大多數問(wèn)題。三種更高的范式:Boyce Codd、第四范式 (4NF) 和第五范式 (5NF) 處理偶爾出現的特殊情況。

第四范式(4NF)

4NF 形式不允許數據庫具有多值依賴(lài)關(guān)系。讓我們看一個(gè)例子來(lái)了解什么是多值依賴(lài)關(guān)系。

想象一下一個(gè)網(wǎng)站,它記錄了披薩店銷(xiāo)售的披薩種類(lèi)和送貨區域。每個(gè)披薩店都可以通過(guò)多種方式銷(xiāo)售披薩,并且可以送貨到多個(gè)地點(diǎn)。披薩店和送貨地點(diǎn)之間以及披薩店和披薩之間存在一對多關(guān)系。但是,披薩類(lèi)型和送貨地點(diǎn)是完全獨立的(假設他們將所有的披薩都送到所有地點(diǎn))。他們銷(xiāo)售的每種披薩類(lèi)型都會(huì )為他們送貨到的每個(gè)送貨區域創(chuàng )建一個(gè)條目。如果一家披薩店銷(xiāo)售 2 種類(lèi)型的披薩并送貨到 3 個(gè)地區。他們將在這個(gè)數據庫中有 6 個(gè)條目。

我們可以說(shuō)

{Pizza Place} ? {Pizza} 和,

{ Pizza Place } ? {Delivery Area}

這里,我們被告知三次,披薩店 P2 出售那不勒斯披薩,如果他們決定將 Deep Dish 添加到菜單中,我們將不得不添加多行。每個(gè)送貨區域各一行。如果未能為其中一個(gè)送貨區域添加一行,將違反多值依賴(lài)關(guān)系,{Pizza Place} ? {Delivery Area}。

為了消除這種不一致的可能性,我們必須將所提供品種的事實(shí)與交貨區域的事實(shí)放入不同的表格中,如下所示。

現在,要添加新的披薩類(lèi)型,我們只需添加一個(gè)條目。要添加新的送貨區域,我們也只需添加一個(gè)條目。

注意:多依賴(lài)關(guān)系只能發(fā)生在具有 3 列或更多列的表中

第五范式(5NF)

讓我們通過(guò)一個(gè)例子來(lái)理解這一點(diǎn)。假設有三家冰淇淋公司,BenJerry's、Haagen Dazs 和 Baskin Robins。每家公司都提供以下產(chǎn)品。

BenJerry's:巧克力片、薄荷、軟糖Haagen Dazs:薄荷、軟糖、香草Baskin Robins:巧克力片、軟糖、香草、薄荷

現在,假設有兩個(gè)人,PersonA 和 PersonB,他們的喜好如下:PersonA:軟糖、薄荷、BenJerry's、Baskin RobbinsPersonB:薄荷、香草、哈根達斯、Baskin Robbins

現在,讓我們看一下名為“人、冰淇淋公司和口味喜好”的表格。

現在,假設 PersonB 最終也開(kāi)始喜歡 Fudge 口味。我們將必須為此添加兩行。(PersonB、Baskin Robbins、Fudge),(PersonB、Haagen Dazs、Fudge)。如果失敗,我們只添加一行。這在邏輯上是錯誤的。如果 PersonB 喜歡 Fudge,并且喜歡 Baskin Robbins 和 Haagen Dazs,那么他們一定喜歡這兩種口味的 Fudge。

為了避免這種不一致,我們一開(kāi)始就不應該創(chuàng )建這個(gè)表。我們可以簡(jiǎn)單地將該表拆分為其組成事實(shí),并在需要上述信息時(shí)執行連接操作。

過(guò)度規范化

過(guò)度規范化數據庫的主要缺點(diǎn)之一是,它會(huì )降低訪(fǎng)問(wèn)數據的查詢(xún)和事務(wù)的性能。這是因為過(guò)度規范化會(huì )創(chuàng )建過(guò)多的表和連接,從而增加磁盤(pán)操作的數量、網(wǎng)絡(luò )流量和內存使用量。此外,過(guò)度規范化還會(huì )降低索引、緩存和分區的效率。

然而,有時(shí)需要達到所需的數據完整性水平。因此,考慮每個(gè)數據庫的要求并在兩者之間找到平衡點(diǎn)非常重要。

小結

在本文中,我們通過(guò)示例研究了規范化的不同形式,為什么規范化數據庫很重要以及過(guò)度規范化可能導致問(wèn)題。

收藏0

發(fā)表評論

訪(fǎng)客

看不清,換一張

◎歡迎參與討論,請在這里發(fā)表您的看法和觀(guān)點(diǎn)。
中文字幕在线永久91_国产一级AV不卡毛片_亚洲日本中文字幕在线四区_日韩黄片在线大全