分享到

簡介

相較於其他更簡單的資料儲存選項,資料庫的主要優勢之一是它們能夠以有序、易於查詢的結構儲存資訊。這些功能源自於資料庫實作綱要 (schemas) 來描述它們儲存的資料。

資料庫綱要 (database schema) 作為資料庫內資料形狀和格式的藍圖。對於關聯式資料庫而言,這包括描述資料類別及其透過表格、主鍵、資料類型、索引和其他物件的關聯性。對於 NoSQL 綱要,這通常涉及根據最重要的預期查詢模式來組織資料。

無論在哪種情況下,了解資料庫綱要的價值,以及如何針對您的需求最佳地設計和優化它都至關重要。本指南將重點介紹什麼是資料庫綱要、您可能會遇到的不同綱要類型、它們為何重要,以及設計自己的綱要時應注意的事項。

為什麼資料庫綱要很重要?

資料庫綱要之所以重要,原因有很多。

無論您的資料來源或應用程式為何,您的資料幾乎總是包含一定的規律性。有些資料是高度規律的,這表示所有資料都可以用相同的模式來描述。有些資料則更不規律,但即便如此,其metadata,也就是關於資料本身的背景資料,通常仍然是規律的。

資料庫綱要告訴資料庫您的資料是什麼以及如何使用它。資料庫綱要幫助資料庫引擎理解這些模式,這使其能夠對資料強制執行約束、在查詢時回應正確的資訊,並以使用者請求的方式操作資料。

良好的綱要傾向於減少隱含資訊,使其對系統及其使用者可見。關聯式資料庫中的綱要可以減少資訊冗餘、確保資料一致性,並提供存取和連接相關資料所需的基本架構和結構。在非關聯式環境中,良好的綱要透過將儲存格式與應用程式至關重要的存取模式對齊,來實現高效能和可擴展性。

定義實體綱要與邏輯綱要

在我們進一步探討之前,我們應該先介紹一些定義。兩個可能令人困惑的術語是實體綱要 (physical schema) 和邏輯綱要 (logical schema)。這兩個術語根據它們使用的情境 (context) 可能傳達不同的含義。

就本文而言,我們主要討論的是設計資料庫綱要時的邏輯綱要和實體綱要。

在設計資料庫綱要時

當談論設計資料庫綱要時,邏輯綱要 (logical schema) 是將資料組織成不同類別、定義資料屬性以及確定資料庫項目最佳結構的一般設計。這個通用文件沒有實作細節,因此與平台無關。它可以被視為藍圖,並在各種資料庫系統中實作。

在相同的背景下,實體綱要 (physical schema) 被認為是設計過程中的下一步,其中實作特定的細節被制定出來。不同實體、約束、鍵、索引和其他項目的名稱被識別並映射到邏輯綱要上。這為使用給定的資料庫平台提供了一個具體的實作計劃。

在這種情況下,邏輯綱要和實體綱要是設計過程的不同階段。該過程的目標是從一組需求中迭代地開發實作計劃,首先佈局資料的抽象品質,然後稍後將該組織映射到您想要使用的資料庫系統的工具集和語言。

在討論資料庫架構時

有時在資料庫的實體和虛擬架構方面也會看到實體綱要和邏輯綱要的另一個情境,指的是實際的資料庫軟體。

在這種情況下,邏輯綱要 (logical schema) 指的是使用者互動的可見資料庫實體。這表示諸如表格、鍵、檢視表和索引等物件是使用者使用資料庫軟體建立和操作的抽象概念。這些項目在系統內的佈局是資料庫呈現的邏輯綱要的一部分。

在相同的背景下,實體綱要 (physical schema) 指的是資料庫軟體在與檔案系統互動時處理資料、檔案和儲存的方式。例如,資料庫架構的實體綱要可以決定系統是否為每個資料庫或每個表格儲存一個單獨的檔案,並決定如何將它們跨多個伺服器進行分割。

靜態綱要與動態綱要

另一個重要的分類可以幫助釐清關聯式和非關聯式資料庫中綱要之間的差異,即靜態綱要和動態綱要之間的差異。

靜態綱要 (static schema) 是通常與關聯式資料庫相關聯的綱要類型。它們預先定義為資料必須遵循才能被系統接受的形狀定義。資料庫系統能夠在使用靜態綱要時強制執行這些模式,因為靜態綱要是對所需狀態的聲明,資料庫系統可以針對輸入進行驗證。

相反地,動態綱要 (dynamic schema) 在非關聯式環境中更為普遍。動態綱要較不 rigid,並且可能缺少任何預先構想的組織結構。相反地,動態綱要根據輸入系統的資料品質浮現 (emerge)。雖然許多非關聯式資料庫可以儲存具有任意內部結構的資訊,但在大多數實際用例中,規律模式往往會浮現。

由於動態綱要是浮現的結構,因此資料庫系統無法將它們用作一致性工具。但是,作為使用者,理解和圍繞它們進行開發仍然非常重要。大致了解您的資料將會是什麼樣子,以及您的應用程式將需要如何與之互動,將有助於您選擇滿足您的需求、效能良好並避免不必要不一致的結構。

設計資料庫綱要

現在您已經了解了一些不同類型的資料庫綱要,您該如何為您的專案設計一個綱要呢?設計有效的綱要需要思考和實踐,以及對問題領域和將使用資料的系統有透徹的理解。

設計過程根據您要設計綱要的資料庫類型而顯著不同。具體而言,靜態綱要的設計過程與動態綱要的設計過程不同。實際上,這些最終與關聯式資料庫 (靜態) 和非關聯式資料庫 (動態) 的設計差異一致。

一般提示

雖然關聯式和非關聯式資料庫的綱要設計存在差異,但有些一般提示適用於任何綱要開發。由於其中許多提示對於設計過程的開始很重要,因此先討論這些提示是有道理的。

了解您的資料

設計綱要的第一步始終應該是了解您的資料和領域。如果不了解資料庫將管理的資訊及其使用的背景,就不可能開發出良好的資料庫設計。

雖然您可能在一開始不會知道資料的所有功能,但盡可能多地了解您的系統預期管理的資料對於設計至關重要。

您應該嘗試回答的一些問題包括

  • 廣泛來說,資料會是什麼?
  • 哪些屬性是重要的記錄項目?
  • 您的總資料集將有多大?
  • 系統累積新資料的速度有多快?
  • 您的資料會是高度規律的嗎?

了解使用模式

同樣地,在不了解使用者需求的情況下設計資料庫綱要,就像其他軟體設計一樣有問題。如果您不是資料將被使用的領域的專家,您需要諮詢該領域的專家來指導您的需求。

您應該問自己諸如以下問題

  • 最常見的查詢是否可預測?
  • 會有多少並行使用者或用戶端?
  • 典型的操作和查詢會觸及多少資料?
  • 大多數請求會是讀取查詢還是寫入查詢?
  • 哪些資料會定期一起查詢?
  • 大多數操作是針對單個記錄還是聚合多個記錄?

制定命名慣例

雖然它可能看起來不重要,但在開發和常規使用期間,設計命名慣例並嚴格遵循它將會有所幫助。

命名和樣式慣例有助於最大限度地減少您在命名新實體時需要執行的心智工作量。同樣地,慣例允許使用者在存取綱要內的不同項目時安全地假設一種模式。某些資料庫系統或資料庫類型已經有流行的命名慣例,您可以遵循這些慣例以避免意外,並避免需要開發自己的標準。

您可能想要考慮的一些樣式和命名慣例

  • 對於區分大小寫的系統,您應該如何使用大寫和小寫字母?
  • 項目何時應該使用單詞的複數形式而不是單數形式?
  • 多字名稱應該用底線、破折號或其他分隔符分隔單詞嗎?
  • 應該始終使用全名,還是在某些情況下允許使用縮寫?

設計關聯式資料庫的綱要

關聯式資料庫通常被認為是靈活的通用解決方案。它們處理 ad-hoc 查詢的能力允許相同的資料庫為不同的應用程式和用例提供服務。因此,當設計關聯式資料庫的綱要時,您的最終目標通常是以一種促進靈活性的方式表示您的資料,同時最大限度地減少資料不一致進入系統的機會。

開發邏輯綱要

關聯式綱要設計通常從邏輯綱要開始,如前一節所述。

您規劃出您想要管理的資料項目、它們的關係以及任何重要的屬性,而無需考慮實作細節或效能標準。此步驟很重要,因為它將您的所有資料項目收集在一個地方,並允許您在抽象層面上梳理它們彼此關聯的方式。

您可以開始草擬代表特定資料項目及其屬性的表格。這種映射過程通常最好用 實體關係 (或 ER) 模型 (entity-relationship (or ER) models) 來表示。ER 模型 (ER models) 是透過定義項目類型及其屬性,然後連接這些項目以規劃出關係和依賴性,從而在視覺上表示資料物件的圖表。

ER 模型經常在早期綱要設計中使用,因為它們非常擅長幫助您弄清楚您有哪些不同的實體、必須管理的屬性、哪些實體彼此相關,以及它們關係的具體性質。使用 ER 模型圖來表示您的邏輯綱要,為您提供了一個關於想要您的資料庫設計成為什麼樣子的穩固計劃,而無需評論實作特定的細節。

開發實體綱要

一旦您有了邏輯綱要,您的下一步就是透過建立實體綱要 (如前一節所述) 來弄清楚具體的實作細節。實體綱要將確切地決定您希望如何使用可用的資料庫結構和功能來實現您的計劃。

第一步通常是瀏覽您的每個資料庫實體,並確定您的主鍵欄位。主鍵 (primary key) 用於唯一識別表格中的每個記錄,以及將不同表格中的記錄綁定在一起。當邏輯綱要中的兩個實體之間存在關係時,您將必須透過引用一個表格中的主鍵作為另一個表格中的外鍵,來連接實體綱要中的兩個表格。這種關係的方向將影響您在使用資料庫時連接不同實體的效能和容易程度。

您在此階段要考慮的另一個因素是預測的查詢模式。某些表格以及這些表格中的欄位將比其他表格和欄位更頻繁地被存取。這些「熱點」是資料庫索引的良好候選者。資料庫索引 (Database indexes) 顯著加快了常用項目的檢索速度,但代價是在資料更新期間效能會更差。確定最初要索引哪些欄位將有助於您平衡這些考量,並定義系統中索引最關鍵的位置。

正規化您的資料結構

在此過程中,您可能會發現將某些元素從邏輯實體中提取到它們自己的獨立表格中更容易。例如,您可能希望從客戶中提取送貨地址,以便多個送貨地址可以與單個客戶關聯,並且產品訂單可以引用特定的地址。這些變更可以被認為是稱為正規化 (normalization) 的過程的一部分。

資料庫正規化 (Database normalization) 是一個確保您的資料庫僅表示每條資料一次,並且不允許導致不一致的更新的過程。正規化是一個龐大的主題,在很大程度上超出了本指南的範圍,但實體綱要設計過程的一部分涉及弄清楚要尋求的正規化程度,並根據需要轉換資料實體以實現該目標。

設計非關聯式和 NoSQL 資料庫的綱要

非關聯式資料庫的設計過程通常看起來截然不同。這種差異很大一部分源於這樣一個事實,即通常選擇非關聯式資料庫是為了在有限數量的預定義查詢上實現高效能。

確定您的主要查詢

非關聯式資料庫綱要通常與將使用它們的應用程式協同設計。綱要反映了應用程式的特定需求,並且在某種意義上,是一種為適應應用程式開發的模型而設計的自訂結構。

由於這種密切的關係,確定您的資料庫必須優化以回應哪些查詢非常重要。第一步是弄清楚您的資料庫需要運行的查詢是什麼。由於您還沒有資料結構,這些將是虛擬查詢,但了解您的應用程式需要哪些資料才能執行某些操作是您的首要目標。

一旦您對您的應用程式需要執行的查詢有了很好的想法,您就需要選擇最重要的查詢來關注。這些是您的應用程式經常執行且無法承受等待的查詢。

定義哪些查詢最重要會告訴您資料結構需要圍繞優化的確切存取模式。資料庫系統儲存和表示資料的方式將對其快速檢索和操作資料項目的能力產生巨大影響。

圍繞您的主要查詢設計您的初始綱要

現在您已經知道您最重要的存取模式,您可以開始開發一個綱要來匹配這些查詢。

此過程的第一步將是確定每個查詢需要返回的確切資訊。然後,規劃出將所有資訊儲存在單個實體中以回應查詢的外觀。

例如,如果您的應用程式將查詢您的資料庫以檢索使用者個人資料資訊,那麼您的起點可能應該是假設所有使用者個人資料資訊都可以儲存在單個位置。

在可能的情況下合併和去重複資料實體

在您確定了需要的屬性並規劃出將與每個查詢相關的所有項目儲存在單個實體中的外觀之後,請檢查是否有重疊。這個想法是在可能的情況下合併資料實體,以減少您的系統將維護的單獨項目的數量。您維護的不同實體類型越多,出現不一致和更新效能問題的可能性就越大。

其中一些重疊之處會相當明顯。如果一個查詢返回的屬性是另一個查詢返回屬性的子集,則可以安全地將這些查詢合併為單一實體。

其他時候,可能更難確定如何映射查詢的資訊。非關聯式資料庫通常不擅長在單一查詢中合併來自多個實體的資料,而關聯式資料庫在這方面通過聯結 (joins) 非常出色。因此,當多個查詢中都存在某些屬性或實體時,您可能必須選擇如何以最佳方式表示這些資料。

判斷您的應用程式可以在哪些地方填補缺口

對於某些查詢,您的應用程式可能需要執行一部分組裝資料的工作,而不是依賴資料庫在單一查詢中回應所有相關資訊。例如,如果您需要處理客戶資訊及其相關訂單,將訂單儲存在不同的類別中,並在您的客戶物件中通過 ID 引用它們可能更有意義。

有些資料庫系統無法通過追蹤物件之間的引用來輕鬆聯結這些資訊。相反,您的應用程式可能需要先查詢客戶,然後使用您找到的訂單 ID 為每個相關訂單發出額外的查詢。

在您的應用程式程式碼中執行這些操作可以幫助繞過某些非關聯式資料庫的限制。這通常比嘗試在單一條目中維護大量資訊,或嘗試為許多不同類型的資料庫物件多次複製資料要好。這些選項可能會導致非常差的效能和資料一致性。

話雖如此,重要的是在您的應用程式程式碼和資料庫結構描述上線後進行測試和調整,以確保您沒有為了快速的資料庫操作而犧牲良好的應用程式效能。一個好的經驗法則是盡可能使用資料庫的功能,因為它們針對資訊檢索和操作進行了高度優化,並在需要時在您的應用程式中進行補充。

判斷適當的分割區鍵

對於高度可擴展的非關聯式資料庫,使用者通常必須判斷分割區或分片鍵。這些鍵將用於在多個伺服器之間分割資料集,以提高效能和回應速度。

找到正確的分割區鍵高度依賴於您的資料和工作負載。然而,一些通用規則可以幫助您。

最好嘗試選擇一個具有相當均勻的鍵分佈的分割區鍵。例如,如果您需要分發客戶資料,他們的出生月份通常會帶來良好的分佈。相反,如果您銷售冬季服裝,註冊月份將不是一個好的分割區鍵,因為您的產品的季節性可能會影響鍵的分佈。對您的候選資料應用雜湊演算法有時也有助於更均勻地分佈您的鍵空間。

另一個考慮因素是您的工作負載是讀取密集型還是寫入密集型。如果您有一個讀取密集型應用程式,您可能希望選擇一個分割區鍵,該鍵允許您將盡可能多的相關資料寫入單一伺服器。這將幫助您避免每次需要檢索相關資料時都必須從多個伺服器讀取。

另一方面,如果您有寫入密集型工作負載,通常最好將寫入分散到盡可能多的伺服器上。如果每個請求最終都將資料寫入同一伺服器,那麼對於寫入密集型操作,您將不會獲得太多效能提升。

總結

設計有效的資料庫結構描述需要耐心、實踐,而且通常需要大量的試錯。

首先,您必須嘗試對您的資料的外觀、您的應用程式將如何使用它,以及需要哪些可用性和資料完整性要求有一個好的想法。之後,您的目標是開發一個反映您資料的特定特徵並促進您預期的用例的結構描述。

結構描述設計,就像任何其他類型的設計一樣,是一個迭代過程。當您對問題空間的理解加深並且真實世界的效能資料變得可用時,預計會更改您的設計。雖然您可能必須隨著時間的推移發展您的結構描述,但從堅實的基礎開始將有助於您完成此過程,並減少未來發生戲劇性、破壞性結構描述更改的可能性。

關於作者
Justin Ellingwood

Justin Ellingwood

Justin 自 2013 年以來一直撰寫關於資料庫、Linux、基礎設施和開發人員工具的文章。他目前與妻子和兩隻兔子住在柏林。他通常不必以第三人稱寫作,這對所有相關方來說都是一種解脫。