數據庫模型設計——主鍵的設計


在數據庫設計時,主要就是對實體和關系的設計,實體表現出來就是表,關系表現出來就是外鍵。而對於一個表,由兩部分組成:主鍵和屬性。主鍵的簡單定義就是表中為每一行數據的唯一標識。其實更准確的說法,每一行數據的唯一標識是候選鍵(Candidate Key),一個表中可以有很多個候選鍵,主鍵是候選鍵中的一個,主要用於更方便的檢索和管理數據。一個表中可以有多個候選鍵,但是只有一個主鍵。由於主鍵常常用於檢索數據,也用於表之間的關聯,所以主鍵的設計的好壞將會嚴重影響數據操作的性能。下面來介紹下主鍵設計的幾個考慮因素。

主鍵的數據類型

最常見的主鍵數據類型是數字類型、固定長度的字符類型和GUID類型。通常情況下,RDBMS會在主鍵上建立聚集索引(SQL Server默認都這么做),由於我們使用B-Tree的數據結構來存儲索引數據,所以一般對主鍵有以下兩個要求:

  • 越短越好——越短在一個Page中存儲的節點越多,檢索速度就越快。
  • 順序增長——如果每一條插入的數據的主鍵都比前面的主鍵大,那么B-Tree上的節點也是順序增長的,不會造成頻繁的B-Tree分割。

越短越好是為了查詢的速度快,順序增長是為了插入速度快。

有了這兩個要求,我們再來分析下各個數據類型:

  • 數字類型:根據數據量決定是用Int16還是Int32或者Int64,能用Int32的就不需要使用Int64。
  • 字符類型:基本不滿足前面提到的2點要求,字符類型一般不會很短,而且也很可能不是順序增長的,所以不是特別推薦的主鍵類型。當然如果確實業務需求使用字符類型,那么也盡量使用char(XX)而不要使用varchar(XX),因為在RDBMS中,對於定長字符串和變成字符串的數據結構和處理是不一樣的,varchar的性能更差。
  • GUID類型:這個類型並不是所有數據庫都有對應的數據類型,SQL Server有uniqueidentifier,MySQL沒有。GUID類型在SQL Server中是16個字節,不算短,比4個字節的Int32長多了。在插入新數據時,GUID一般都是使用NewId()這樣的生成隨機GUID的方式生成的,所以也不是順序增長的,在插入速度上不會很快。

通過上面的比較,我們知道使用數字類型是更好的方式,那么我們為什么還會有人使用GUID和字符串來當主鍵呢?那是因為:

相對於數字類型,字符類型更易讀易記,在檢索關聯的數據時,更方便直接。

GUID的優勢是全球唯一,也就是說同樣的系統,如果部署了多套環境,那么里面的數據的主鍵仍然是唯一的,這樣有助於數據的集成。典型的例子就是一個系統在全國每個省份都部署一套,每個省份的數據各種錄入,互不干擾,然后再把每個省的數據集成起來為總部做分析。

數據庫主鍵與業務主鍵

前面說到一個表可能有很多個唯一標識的候選鍵,那么這么多候選鍵中,哪個應該拿來做主鍵呢?一種方案是再新建一個獨立的字段作為主鍵,該字段並沒有業務含義,只是一個自增列或者流水號,用於唯一標識每一行數據,這是數據庫主鍵。另外一種方案是選擇其中較短較常用的屬性作為主鍵,這是業務主鍵。個人建議是不要使用任何有業務含義的字段作主鍵,而是使用一個自增的(或者系統生成的)沒有實際業務意義的字段作為主鍵。為什么呢?主要是出於以下考慮:

具有業務意義的字段很可能是用戶從系統錄入的,不要信任用戶的任何輸入,只要是用戶自己錄入的,那么就很有可能錄錯了,如果發現錄入錯誤,這個時候再對主鍵進行修改,將會涉及到大量關聯的外鍵表的修改,是很麻煩的一件事情。比如在做人員表的時候,就不要使用員工號或者身份證號做主鍵。

具有業務意義的字段雖然在當前階段是唯一的,是不變的,但是並不能保證隨着公司政策變動、業務調整等原因,導致該業務字段需要修改,以滿足新的業務要求,這個時候要修改主鍵也是很麻煩的事情。比如部門表,我們以部門Code作為主鍵,但是后來部門變動,Code修改,則系統部門表的主鍵也得更改。

還有一個原因是業務主鍵在數據錄入的時候不一定是明確知道的,有時我們會在不知道業務主鍵的情況下,就錄入其他相關信息,這個時候,如果使用業務主鍵做數據庫的主鍵,那么數據將無法錄入。比如員工表把員工號作為主鍵,那么員工還沒有入職,沒有員工號的時候,HR需要先維護一些該預入職員工的信息是不可能的。

聯合主鍵

聯合主鍵就是以多個字段來唯一標識每一行數據。前面已經說到主鍵應該越短越好,而且是建議是一個沒有意義的自增列,那么是不是就不會再需要聯合主鍵呢?答案是否定的,我們仍然可能會使用到聯合主鍵。聯合主鍵主要使用在多對多的關系時,中間表就需要使用聯合主鍵。在簡單的多對多關系中,我們不需要為中間的關聯建立實體,所以中間表可能就只需要兩列,分別是兩個實體表的主鍵。

主鍵值的生成

主鍵值的生成可以參考NHibernate的配置,概況下來主要有這么幾種生成方式:

  • 自增,這是SQL Server常用的主鍵生成方式,完全由數據庫管理主鍵的值。
  • Sequence對象,這是Oracle常用的主鍵生成方式,現在SQL Server已支持。主要是在數據庫中有一個Sequence對象,通過該對象生成主鍵。
  • GUID,這是用於GUID類型的主鍵,可以使用newid()這種數據庫提供的函數,或者使用程序生成Guid並賦值。
  • Hilo值,這是一種使用高低位算法生成的數字值的主鍵。該值由NHibernate程序內部生成。
  • 其他程序賦值,完全由程序根據自己的算法生成並賦值。

更詳細的主鍵生成,我們可以參見:http://www.cnblogs.com/chenkai/archive/2009/04/13/1434912.html

主鍵與索引

在概念和作用上,主鍵與索引是完全兩個不同的東西,但是由於我們大部分情況下都是使用主鍵檢索數據,所以大部分數據庫的默認實現,在建立主鍵時會自動建立對應的索引。

以SQL Server為例,默認情況下,建立主鍵的列,就會建立聚集索引,但是實際上,我們可以在建立主鍵時不使用聚集索引。另外還有一個唯一約束(索引)的概念,該索引中的數據必須是唯一不能重復的,感覺和主鍵的意義一樣,但是還是有一點點區別。

主鍵是只能由一個,而唯一約束(索引)在一個表中可以有多個。

主鍵不能為空,而唯一約束(索引)是可以為空的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM