1. 序言
當前,隨著信息量的急劇增加,對於數據的存儲和管理方式,各企業都逐漸擺脫了之前的依靠文件系統(文本文件或者Excel)或者一些桌面型的小型數據庫系統(如Access、FoxBASE或者DBase)的狀態,轉而通過一些大型數據庫來管理企業的信息。這些大型數據庫系統包括Oracle、MS SQL Server或者IBM DB2。盡管目前數據庫系統也在向面向對象的數據庫系統方向發展,但是上述的傳統的關系型數據庫系統依然占據著主要位置。
筆者從九十年代末開始以關系型數據庫系統為基礎為客戶進行管理軟件的定制化開發。主要是以PowerBuilder為前台開發工具,開發出一些列的C/S結構的軟件。進入到本世紀,尤其是最近兩年,筆者又以Visual Studio 2003為工具,開發了一些B/S結構的應用。但是,無論是使用何種開發工具,還是開發何種結構的軟件,其後台數據庫系統依舊是關系型數據庫系統。根據客戶的應用環境,主要是在MS SQL Server數據庫上進行開發,當然也有基於Oracle數據庫的軟件開發。
也正是因為數據量信息量的增加,采用大型的關系型數據庫系統作為企業的數據存儲管理方式,也就要求基於數據庫開發的開發者在數據庫設計時必須遵循相應的規范。關於數據庫邏輯設計,最重要的就是數據庫表的設計,都有一套相應的理論支持,比如要滿足相應的范式要求。一般而言,數據庫表設計滿足第二或者第三范式即可。
在開發過程中,也盡量遵循這些相應的規則,但由於之前的經驗所限或者是在詳細設計時做的工作不夠充分,導致一些表結構不是很合理。正是這些不合理,目前出現一些問題,並且已經在部分系統中有所體現。
關於數據庫的邏輯設計,是一個很廣泛的問題。本文主要針對筆者開發應用中的現狀,論述在MS SQL Server上進行表設計時,對表的主鍵設計應注意的問題以及相應的解決辦法。
2.主鍵設計現狀和問題
2.1 現狀
關於數據庫表的主鍵設計,一般而言,是根據業務需求情況,以業務邏輯為基礎,形成主鍵。
比如,銷售時要記錄銷售情況,一般需要兩個表,一個是銷售單的概要描述,記錄諸如銷售單號、總金額一類的情況,另外一個表記錄每種商品的數量和金額。對於第一個表(主表),通常我們以單據號為主鍵;對於商品銷售的明細表(從表),我們就需要將主表的單據號也放入到商品的明細表中,使其關聯起來形成主從關系。同時該單據號與商品的編碼一起,形成明細表的聯合主鍵。這只是一般情況,我們稍微將這個問題延伸一下:假如在明細中,我們每種商品又可能以不同的價格方式銷售。有部分按折扣價格銷售,有部分按正常價格銷售。要記錄這些情況,那麼我們就需要第三個表。而這第三個表的主鍵就需要第一個表的單據號以及第二個表的商品號再加上自身需要的信息一起構成聯合主鍵;又或者其他情況,在第一個主表中,本身就是以聯合方式構成聯合主鍵,那麼也需要在從表中將主表的多個字段添加進來聯合在一起形成自己的主鍵。
筆者在以前的項目中,也基本上是采取這樣的表設計思路來設計系統的表結構和主鍵。
2.2 存在的問題
在上面小節中,我們描述了當前在表的主鍵設計時的現狀。從中我們不難看出存在這樣的問題:
數據冗余存儲:隨著這種主從關系的延伸,數據庫中需要重復存儲的數據將變得越來越龐大。或者當主表本身就是聯合主鍵時,就必須在從表中將所有的字段重新存儲一次。
SQL復雜度增加:當存在多個字段的聯合主鍵時,我們需要將主表的多個字段與子表的多個字段關聯以獲取滿足某些條件的所有詳細情況記錄。
程序復雜度增加:可能需要傳遞多個參數。
效率降低:數據庫系統需要判斷更多的條件,SQL語句長度增加。同時,聯合主鍵自動生成聯合索引
WEB分頁困難:由於是聯合主鍵方式(對於多數的子表),那麼在WEB頁面上要進行分頁處理時,在自關聯時,難於處理。