開發人員如何有效地進行數據庫設計

jopen 11年前發布 | 9K 次閱讀 數據庫設計

  數據庫設計在軟件開發過程中占有重要的地位,國內開發者 MeteorSeed 在博客中結合自己的實際經歷全面總結了關系型數據庫設計需要注意的各個方面,包括 Codd 的基本法則、設計階段、設計原則和命名規則。

  MeteorSeed 認為在項目早期應該由開發者進行數據庫設計,后期調優則需要 DBA:“一個精通 OOP 和 ORM 的開發者,設計的數據庫往往更為合理,更能適應需求的變化”。他引用了關系數據庫之父 Codd 的 12 條法則,作為數據庫設計的指導性方針:

  1. 信息法則 關系數據庫中的所有信息都用唯一的一種方式表示——表中的值。
  2. </ol>

    • 保證訪問法則 依靠表名、主鍵值和列名的組合,保證能訪問每個數據項。
    • </ul>

      • 空值的系統化處理 支持空值(NULL),以系統化的方式處理空值,空值不依賴于數據類型。
      • 基于關系模型的動態聯機目錄 數據庫的描述應該是自描述的,在邏輯級別上和普通數據采用同樣的表示方式,即數據庫必須含有描述該數據庫結構的系統表或者數據庫描述信息應該包含在用戶可以訪問的表中。
      • 統一的數據子語言法則 一個關系數據庫系統可以支持幾種語言和多種終端使用方式,但必須至少有一種語言,它的語句能夠一某種定義良好的語法表示為字符串,并能全面地支持以下所有規則:數據定義、視圖定義、數據操作、約束、授權以及事務。(這種語言就是 SQL)
      • 視圖更新法則 所有理論上可以更新的視圖也可以由系統更新。
      • 高級的插入、更新和刪除操作 把一個基礎關系或派生關系作為單個操作對象處理的能力不僅適應于數據的檢索,還適用于數據的插入、修改個刪除,即在插入、修改和刪除操作中數據行被視作集合。
      • 數據的物理獨立性 不管數據庫的數據在存儲表示或訪問方式上怎么變化,應用程序和終端活動都保持著邏輯上的不變性。
      • 數據的邏輯獨立性 當對表做了理論上不會損害信息的改變時,應用程序和終端活動都會保持邏輯上的不變性。
      • 數據完整性的獨立性 專用于某個關系型數據庫的完整性約束必須可以用關系數據庫子語言定義,而且可以存儲在數據目錄中,而非程序中。
      • 分布獨立性 不管數據在物理是否分布式存儲,或者任何時候改變分布策略,RDBMS 的數據操縱子語言必須能使應用程序和終端活動保持邏輯上的不變性。
      • 非破壞性法則 如果一個關系數據庫系統支持某種低級(一次處理單個記錄)語言,那么這個低級語言不能違反或繞過更高級語言(一次處理多個記錄)規定的完整性法則或約束,即用戶不能以任何方式違反數據庫的約束。
      • </ul>

          MeteorSeed 把數據庫設計階段分為規劃階段、概念階段、邏輯階段、實現階段和物理階段。關于設計原則,他從以下幾個方面闡述了自己的經驗:

        • 降低對數據庫功能的依賴 功能應該由程序實現,而非 DB 實現。原因在于,如果功能由 DB 實現時,一旦更換的 DBMS 不如之前的系統強大,不能實現某些功能,這時我們將不得不去修改代碼。所以,為了杜絕此類情況的發生,功能應該有程序實現,數據庫僅僅負責數據的存儲,以達到最低的耦合。
        • </ul>

          • 定義實體關系的原則 當定義一個實體與其他實體之間的關系時,需要考量如下:
          • 牽涉到的實體 識別出關系所涉及的所有實體。
          • 所有權 考慮一個實體“擁有”另一個實體的情況。
          • 基數 考量一個實體的實例和另一個實體實例關聯的數量。
          • </ul>

              關系與表數量

            • 描述1:1 關系最少需要 1 張表。
            • 描述1:n關系最少需要 2 張表。
            • 描述n:n關系最少需要 3 張表。
            • 列意味著唯一的值 如果表示坐標(0,0),應該使用兩列表示,而不是將“0,0”放在 1 個列中。
            • </ul>

              • 列的順序 列的順序對于表來說無關緊要,但是從習慣上來說,采用“主鍵+外鍵+實體數據+非實體數據”這樣的順序對列進行排序顯然能得到比較好的可讀性。
              • 定義主鍵和外鍵 數據表必須定義主鍵和外鍵(如果有外鍵)。定義主鍵和外鍵不僅是 RDBMS 的要求,同時也是開發的要求。幾乎所有的代碼生成器都需要這些信息來生成常用方法的代碼(包括 SQL 文和引用),所以,定義主鍵和外鍵在開發階段是必須的。之所以說在開發階段是必須的是因為,有不少團隊出于性能考慮會在進行大量測試后,在保證參照完整性不會出現大的缺陷后,會刪除掉 DB 的所有外鍵,以達到最優性能。MeteorSeed 認為,在性能沒有出現問題時應該保留外鍵,而即便性能真的出現問題,也應該對 SQL 文進行優化,而非放棄外鍵約束。
              • 選擇鍵
              • </ul>

                  人工鍵與自然鍵。人工鍵——實體的非自然屬性,根據需要由人強加的,如 GUID,其對實體毫無意義;自然鍵——實體的自然屬性,如身份證編號。人工鍵的好處:鍵值永遠不變;永遠是單列存儲。人工鍵的缺點:因為人工鍵是沒有實際意義的唯一值,所以不能通過人工鍵來避免重復行。MeteorSeed 建議全部使用人工鍵。原因如下:

                • 在設計階段我們無法預測到代碼真正需要的值,所以干脆放棄猜測鍵,而使用人工鍵。
                • 人工鍵復雜處理實體關系,而不負責任何屬性描述,這樣的設計使得實體關系與實體內容得到高度解耦,這樣做的設計思路更加清晰。
                • </ul>

                    MeteorSeed 的另一個建議是——每張表都需要有一個對用戶而言有意義的自然鍵,在特殊情況下也許找不到這樣一個項,此時可以使用復合鍵。這個鍵我在程序中并不會使用其作為唯一標識,但是卻可以在對數據庫直接進行查詢時使用。使用人工鍵的另一個弊端,主要源自對查詢性能的考量,因此選擇人工鍵的形式(列的類型)很重要:

                  • 自增值類型,由于類型輕巧查詢效率更好,但取值有限。
                  • GUID 查詢效率不如值類型,但是取值無限,且對開發人員更加親切。
                  • </ul>

                      智能健與非智能鍵。智能鍵——鍵值包含額外信息,其根據某種約定好的編碼規范進行編碼,從鍵值本身可以獲取某些信息;非智能鍵,單純的無意義鍵值,如自增的數字或 GUID。智能鍵是一把雙刃劍,開發人員偏愛這種包含信息的鍵值,程序盼望著其中潛在的數據;數據庫管理員或者設計者則討厭這種智能鍵,原因也是很顯然的,智能鍵對數據庫是潛在的風險。前面提到,數據庫設計的原則之一是不要把具有獨立意義的值的組合實現到一個單一的列中,應該使用多個獨立的列。數據庫設計者,更希望開發人員通過拼接多個列來得到智能鍵,即以復合主鍵的形式給開發人員使用,而不是將一個列的值分解后使用。開發人員應該接受這種數據庫設計,但是很多開發者卻想不明白兩者的優略。MeteorSeed 認為,使用單一列實現智能鍵存在這樣一個風險,就是我們可能在設計階段無法預期到編碼規則可能會在后期發生變化。比如,構成智能鍵的局部鍵的值用完而引起規則變化或者長度變化,這種編碼規則的變化對于程序的有效性驗證與智能鍵解析是破壞性的,這是系統運維人員最不希望看到的。所以 MeteorSeed 建議如果需要智能鍵,請在業務邏輯層封裝(使用只讀屬性),不要再持久化層實現,以避免上述問題。

                      除此之外,MeteorSeed 還從“是否允許 NULL”、屬性切割、規范化(范式)、選擇數據類型、優化并行等幾個方面談了設計原則。有關詳細內容,可以查看 MeteorSeed 的博客原文
                    來自: InfoQ

                     本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
                     轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
                     本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!