zoukankan      html  css  js  c++  java
  • 【转】关于使用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

     

     ________________________________________________________________

    1
    string str =  Guid.NewGuid().ToString("B");  //生成guid,并用{}包括guid值
  • 相关阅读:
    js-排序算法
    django csrf token添加
    django mongodb配置
    django logging
    linux文件行首行尾添加或替换
    linux 大小写转化
    linux $参数
    mysql 基本操作
    生产者消费者示例
    python smtplib发email
  • 原文地址:https://www.cnblogs.com/liuslayer/p/9122470.html
Copyright © 2011-2022 走看看