【轉】關於使用GUID和Identity做主鍵的一些思考


 

 
 
 
 
 
 
 

通常,給數據庫中的表都添加一個“無意義”的主鍵,能夠大大地簡化程序的開發。這個主鍵用什么類型呢?其實各種類型,只要大小不超過900字節都可以,但我們最常面臨的兩種選擇是——GUID(UniqueIdentifity)和Identity INT。

《ADO.NET 2.0高級編程》一書的“5.2.2 選擇主鍵”一節,對此進行了一些對比,並推薦使用GUID類型作為主鍵的類型。但本文中老劉將介紹自己在實際開發中的一些感觸。

老劉在公司寫程序時,面對的數據庫絕大多數都是用Identity做主鍵;而回家自己寫程序玩的時候,因為迷信《ADO.NET 2.0高級編程》,所以設計的數據庫都采用GUID做主鍵類型。所以,對這兩種主鍵類型都有些想法。

GUID優於Identify的方面

首先,對於GUID類型的主鍵,通常在創建新的數據條目時可以采用Guid.NewGuid()方法為其生成主鍵;而對於Identify類型的主鍵,只有當數據條目被真正插入數據庫后才能得到其主鍵值。當需要在同一個事務中,向多個相關表中插入數據時,若采用GUID主鍵,就能使用一次提交動作插入所有數據;而如果使用Identify類型做主鍵,就必須先插入主鍵列所在表的數據,再插入外鍵列所在表的數據。如下面兩段代碼所示。

//  使用GUID作為主鍵類型
using (MyDataContext db  =   new  MyDataContext())
{
    Category c 
= new Category
    
{
        Id 
= Guid.NewGuid(),
        Name 
= "分類1"
    }
;
    Article a 
= new Article
    
{
        Id 
= Guid.NewGuid(),
        Title 
= "標題1",
        Body 
= "內容",
        CategoryId 
= c.Id    // Category對象的Id已經確定
    }
;
    db.Categories.InsertOnSubmit(c);
    db.Articles.InsertOnSubmit(a);

    db.SubmitChanges();    
// 一次提交,如果出現錯誤自動全部回滾
}


//  使用Identity作為主鍵類型
using (MyDataContext db  =   new  MyDataContext())
{
    Category c 
= new Category    // 由於才用Identity類型作為主鍵,所以無需也不能明確指定主鍵值
    {
        Name 
= "分類2"
    }
;
    db.Categories.InsertOnSubmit(c);
    db.SubmitChanges();    
// 提交后才能得到確定的ID值

    Article a 
= new Article
    
{
        Title 
= "標題又來了",
        Body 
= "沒有內容",
        CategoryId 
= c.Id
    }
;
    db.Articles.InsertOnSubmit(a);
    db.SubmitChanges(a);    
// 第二個提交,如果出錯,分類c也會留在數據庫中
}

正如注釋中所述,當發生錯誤時,一次提交可以簡單干凈地回滾;但多次提交,就得采取一些手段了。

Identify優於GUID的方面

首先,Identify根本上說是一個int,只占4字節;而GUID要占16字節。這當然不算什么,可以忽略。

其次,要知道,主鍵就是一個簇索引(聚集索引),這意味着數據在磁盤上的物理排列順序是和主鍵順序一樣的。這就存在一個問題,每次生成的GUID並不是按照時間順序從小到大的,換句話說,第二次生成的GUID可能比第一次小,而第三次可能又比第二次小。這就導致每次插入一行數據時,都要對表中整行整行的數據進行排序。而Identify類型的字段,可以明確保障后生成的值比之前生成的值都大,因此新插入的數據會簡單地追加在表的尾部。所以,對於頻繁插入新數據的表來說,Identify主鍵的性能要好一些。(注意,本條純屬老劉推測,沒有進行過測試。)

最后,Identify主鍵更便於人類閱讀。嗯……給大家各場景吧。在公司,我沒有查看生產環境數據庫的權限,所以當客戶提交來bug之后,我會朝我老板喊:幫我把服務器上ID是1234的用戶的數據取出來我看看~~  想想吧,如果采用了GUID主鍵,我該怎么喊?

-----

注,寫到這里,就完了。但我發現好像有些傾向於Identify主鍵。希望大家不要有這樣的偏見,好好看看《ADO.NET 2.0高級編程》,考慮考慮。歡迎大家在這里探討。

 

轉自:http://www.cnblogs.com/AndersLiu/archive/2008/07/03/primer-key-guid-vs-identify-int.html

 

 

 

 

Guid在數據庫的應用

GUID(Global unique identifier)全局唯一標識符,它是由網卡上的標識數字(每個網卡都有唯一的標識號)以及 CPU 時鍾的唯一數字生成的的一個 16 字節的二進制值。

GUID 的格式為“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每個 x 是 0-9 或 a-f 范圍內的一個十六進制的數字。例如:6F9619FF-8B86-D011-B42D-00C04FC964FF 即為有效的 GUID 值。
世界上的任何兩台計算機都不會生成重復的 GUID 值。GUID 主要用於在擁有多個節點、多台計算機的網絡或系統中,分配必須具有唯一性的標識符。在 Windows 平台上,GUID 應用非常廣泛:注冊表、類及接口標識、數據庫、甚至自動生成的機器名、目錄名等。
在這次開發 ASP.NET 應用時,我大量使用了類型為 GUID 的 ID 列作為各實體表的關鍵字(鍵)。由於其唯一、易產生的特性,給應用程序處理帶來諸多好處。
1、在 SQL Server 中使用 GUID
如果在 SQL Server 的表定義中將列類型指定為 uniqueidentifier,則列的值就為 GUID 類型。
SQL Server 中的 NewID() 函數可以產生 GUID 唯一值,使用此函數的幾種方式如下:
1) 作為列默認值
將 uniqueidentifier 的列的默認值設為 NewID(),這樣當新行插入表中時,會自動生成此列 GUID 值。

2)使用 T-SQL
在 T-SQL 中使用 NewID()函數,如“INSERT INTO Table(ID,... ) VALUES(NewID(),...)”來生成此列的 GUID 值。
3)提前獲取 GUID 值
由於特殊功能需要,需要預先獲知新行的 ID 值,也可以使用如下 C# 代碼提前獲得 GUID 的值,再存儲到數據庫中:
 SqlCommand cmd = New SqlCommand();
 cmd.CommandText = "SELECT NewID()";
 string rowID = (string) cmd.ExecuteScalar();
 cmd.CommandText = "INSERT INTO Table(ID,...) VALUES(@ID,...)
 cmd.Parameters.Add("@ID",SqlDbType.UniqueIdentifier).Value = new Guid(rowID);
 cmd.ExecuteNoQuery();
uniqueidentifier 值不能進行算術運算,但可以進行(意義不大的)比較操作和 NULL 檢查;它不能象 IDENTITY 列一樣,可以獲知每行的增加時間的先后順序,只能通過增加其它時間或時間戳列來完成此功能。
2、在 .NET 中使用 GUID
GUID 在 .NET 中使用非常廣泛,而且 .NET Framework 提供了專門 Guid 基礎結構。
Guid 結構的常用法包括:
1) Guid.NewGUID()
生成一個新的 GUID 唯一值
2) Guid.ToString()
將 GUID 值轉換成字符串,便於處理
3)構造函數 Guid(string)
由 string 生成 Guid 結構,其中string 可以為大寫,也可以為小寫,可以包含兩端的定界符“{}”或“()”,甚至可以省略中間的“-”,Guid 結構的構造函數有很多,其它構造用法並不常用。
同時,為了適用數據庫中使用 GUID 的需要,.NET Framework 也提供了 SqlGUID 結構,它和 Guid 結構類似,只是兩者對排序(CompareTo)的處理方式不同,SqlGuid 計算值的最后 6 個字節。而 Guid 計算全部 16 個字節,這種差異可能會給 SQL Server 中 uniqueidentifier 列的排序帶來一定影響,當然這種排序意義也不大。
.NET Framework 中可以使用類 GuidConverter 提供將 Guid 結構與各種其他表示形式相互轉換的類型轉換器。

3、GUID 的優缺點
1) 優點
  • 同 IDENTITY 列相比,uniqueidentifier 列可以通過 NewID() 函數提前得知新增加的行 ID,為應用程序的后續處理提供了很大方便。

  • 便於數據庫移植,其它數據庫中並不一定具有 IDENTITY 列,而 Guid 列可以作為字符型列轉換到其它數據庫中,同時將應用程序中產生的 GUID 值存入數據庫,它不會對原有數據帶來影響。

  • 便於數據庫初始化,如果應用程序要加載一些初始數據, IDENTITY 列的處理方式就比較麻煩,而 uniqueidentifier 列則無需任何處理,直接用 T-SQL 加載即可。

  • 便於對某些對象或常量進行永久標識,如類的 ClassID,對象的實例標識,UDDI 中的聯系人、服務接口、tModel標識定義等。
2) 缺點
    • GUID 值較長,不容易記憶和輸入,而且這個值是隨機、無順序的,所以使用時要注意場合,最好不要嘗試用它來作為你的電子郵件地址 J

    • GUID 的值有 16 個字節,與其它那些諸如 4 字節的整數相比要相對大一些。這意味着如果在數據庫中使用 uniqueidentifier 鍵,可能會帶來兩方面的消極影響:存儲空間增大;索引時間較慢。

轉自:http://blog.csdn.net/xfworld/article/details/1483308

 

 

 

ACCESS中使用GUID全局唯一標識符的自動唯一編號[同步復制ID]之解決方法   http://blog.csdn.net/johnsuna/article/details/2322001

背景:

這段時間臨時為一個旅游類網站制作一些網站程序。數據表的情況大致如下: 數據庫表匯總 圖1 數據庫表的大致情況 由於是Access數據庫,之前有兩個數據表:TC_TourCompany和TC_SubDetail,前者是旅行社名錄相關資料(為了方便描述,暫且叫“總公司表”),后者是下屬營業部(如果有的話)的相關資料(為方便描述,暫且叫“子公司表”)。

由於業務需要,想將之擴展為適用於所有“公司類”(比如酒店、景區、景點、漂流公司、娛樂餐飲、機票代理、交通公司等)的數據表,由於酒店、餐飲娛樂、機票代理等公司都有可能有分部或分公司,所以表的數據結構是差不多的。所以,我們可以通用這樣的數據表設計來簡化今后的程序開發。當然,我們需要在數據表中新增一列,用於描述公司的類型是旅行社、酒店、景區或是娛樂餐飲類公司等。不在本文的敘述范圍,按下不表。

為了方便今后的分類搜索查詢,確保公司(包括子公司)的唯一性,所以,我想在上述兩個表中增加一列,我把列名叫做GUID。它的每條記錄都是唯一不重復的值,類似:{9E4038C8-E965-45B1-BDE1-9F06E6B280A3},這有點象.Net中的System.Guid.NewGuid()生成的值,並用大括號{}包含起來。

做法: 如何在已有數據庫表記錄的情況下自動生成每一條記錄的這些值呢?

一開始,我走了點彎路。在新增GUID列時,我選擇了此列的數據類型為“數字”並在下面常規選項卡中“字段大小”中選擇了“同步復制 ID”,索引中選擇了“有(無重復)”。本以為這樣保存結構之后就萬事大吉,最終打開表的所有記錄時發現,GUID列完全為空,沒有任何值!於是,我想了一些辦法去插入GUID唯一值。方案之一是在ACCESS中使用SQL語句更新,后來發現此路不通。方案之二就是使用ADO.net編程方式更新表記錄,工作量也不小。

有沒有更好的辦法呢?一個偶爾的想法讓我找到了更快更好的解決辦法,那就是在設計視圖中建立GUID列時,數據類型選擇自動編號而不是數字!同時,在下面常規選項卡中“字段大小”中選擇了“同步復制 ID”,索引中選擇了“有(無重復)”。

如下圖: 設計視圖中增加GUID列 圖2  給總公司名錄表(TC_TourCompany表)增加GUID列

在設計視圖中給子公司增加GUID列 圖3 給總公司表(TC_TourCompany表)增加GUID列后自動生成GUID記錄值 在設計視圖中給分公司(分部)表增加GUID列 圖4  給分公司(分部)TC_SubDetail表增加GUID列

給分公司(分部)增加GUID列后自動生成GUID記錄值 圖5 給分公司(分部)TC_SubDetail表增加GUID列后自動生成GUID記錄值

以后新增記錄時會發生什么?經測試發現,ACCESS會自動搞定生成GUID記錄值的問題。OK,完美!

更多的話: 從 Access 生成 SQL 語句時,遇到了 Guid 查詢的問題,在 SQL Server 中使用的字符串形式,不能查詢出任何數據。

SELECT * FROM tableName WHERE [GUID]='12345678-90AB-CDEF-1234-567890ABCDEF'

如果條件字符串所引用的列為 GUID 類型,那么該條件表達式使用的語法稍微有所不同: WHERE [GUID] ={GUID {12345678-90AB-CDEF-1234-567890ABCDEF}} 請確保包含如上所示的嵌套大括號和連字號。 需要注意的是,嵌入大括號的方法只用於 Where 語句,在 Insert 語句中還是要使用單引號,否則將產生MALFORMED GUID in query 的錯誤。

更多參考: ASP.NET開發經驗(3) --- 使用 GUID 值來作為數據庫行標識 http://blog.joycode.com/moslem/archive/2004/03/23/16930.aspx

其他: 導出/打印Access數據庫的結構 http://blog.csdn.net/johnsuna/archive/2008/05/05/2393664.aspx

附錄:

Access數據類型與.net OleDbType枚舉類型的對應

最常見的數據類型映射列表

 

訪問類型名稱 數據庫數據類型 OLEDB 類型 .NET 框架類型 成員名稱
文本 VarWChar DBTYPE _ WSTR System.String OleDbType.VarWChar
備忘錄 LongVarWCha R DBTYPE _ WSTR System.String OleDbType.LongVarWChar
字節數: UnsignedTinyInt DBTYPE _ UI 1 System.Byte OleDbType.UnsignedTinyInt
是/否 Boolean DBTYPE_BOOL System.Boolean OleDbType.Boolean
日期 / 時間 DateTime DBTYPE _ DATE System.DateTime OleDbType.date
貨幣 十進制 DBTYPE_NUMERIC System.Decimal OleDbType.numeric
十進制數: 十進制 DBTYPE_NUMERIC System.Decimal OleDbType.numeric
雙精度數字: 雙精度數字 DBTYPE_R8 System.Double OleDbType.Double
自動數字(復制 ID) GUID DBTYPE_GUID System.Guid OleDbType.guid
復制 (ID) 號: GUID DBTYPE_GUID System.Guid OleDbType.guid
自動數字(長整型) 整數 DBTYPE_I4 System.Int 32 OleDbType.integer
數量: (長整型) 整數 DBTYPE_I4 System.Int 32 OleDbType.integer
OLE 對象 LongVarBinary DBTYPE_BYTES 數組 System.Byte OleDbType.LongVarBinary
單精度數字: 單精度數字 DBTYPE_R4 System.Single OleDbType.single
整型數: SmallInt DBTYPE_I2 System.Int 16 OleDbType.SmallInt
二進制 VarBinary * DBTYPE_BYTES 數組 System.Byte OleDbType.binary
超鏈接 VarWChar DBTYPE _ WSTR System.String

OleDbType.VarWChar

 

 ________________________________________________________________

 

string str =  Guid.NewGuid().ToString("B");  //生成guid,並用{}包括guid值

  


免責聲明!

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



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