原文:使用NEWSEQUENTIALID解决GUID聚集索引问题

UNIQUEIDENTIFIER做主键(Primary Key)是一件很方便的事情,在数据合并等操作中有不可替代的优势

但是由于普通的GUID的分散性使得如果主键加上聚集索引(Clustered Index)会导致在插入记录时效率大大降低



SQL SERVER 2005中新增了一个NEWSEQUENTIALID的函数,MSDN的解释是:

在指定计算机上创建大于先前通过该函数生成的任何 GUID 的 GUID。

NEWSEQUENTIALID() 不能在查询中引用。

注:即只能做为数据库列的DEFAULT VALUE,不能执行类似SELECT NEWSEQUENTIALID()的语句

只有当计算机没有网卡时,NEWSEQUENTIALID() 生成的 GUID 才在该特定计算机中是唯一的。

注:这句话是错误的,应该是只有只有当计算机有网卡时,生成的GUID才是全球唯一

您可以使用 NEWSEQUENTIALID() 生成 GUID 以减少叶级别索引上的页争用。



但是使用NEWSEQUENTIALID却不是那么一帆风顺

1. 如何获得生成的GUID

如果生成的GUID所在字段做为外键要被其他表使用,我们就需要得到这个生成的值

通常,PK是一个IDENTITY字段,我们可以在INSERT之后执行 SELECT SCOPE_IDENTITY()来获得新生成的ID

但是由于NEWSEQUENTIALID()不是一个INDETITY类型,这个办法是做不到了,而他本身又只能在默认值中使用,不可以事先SELECT好再插入,那么我们如何得到呢?有以下两种方法:

--1. 定义临时表变量 

DECLARE @outputTable TABLE(ID uniqueidentifier)

INSERT INTO TABLE1(col1, col2)

OUTPUT INSERTED.ID INTO @outputTable

VALUES('value1', 'value2')

SELECT ID FROM @outputTable



--2. 标记ID字段为ROWGUID(一个表只能有一个ROWGUID)

INSERT INTO TABLE1(col1, col2)

VALUES('value1', 'value2')

--在这里,ROWGUIDCOL其实相当于一个别名

SELECT ROWGUIDCOL FROM TABLE1

2. 如何设定DEFAULT VALUE为NEWSEQUENTIALID()

通过UI的方式设定默认值时,由于SQL SERVER 2005的BUG(即使是SP2也没有解决),导致我们设置了默认值为NEWSEQUENTIALID()保存时会出现以下错误:

Warning were encountered during the pre-save validation process, and might result in a failure during save. Do you want to continue attempting to save?

'Table1' Table

-Error validating the default for column 'Id'

有两种方式可以解决:要么直接点Yes,要么通过CREATE TABLE语句来建表。



通过客户端的方式,也可以通过调用windows api产生sequential的guid,虽说可以省去上面提到的两种麻烦,但是经过我测试,效果不是那么好。

我建立了一个表有ID和TIMESTAMP两个字段,用NEWSEQUENTIALID()和客户端两种方法生成记录,并按ID和TIMESTAMP两种方式进行排序。

NEWSEQUENTIALID()版本的结果永远一样。而客户端生成就有一些问题,如果连续运行程序,表现良好,如果间隔一段时间后继续运行,新生成的记录就不一定大于之前生成的记录,而每次间隔之间连续运行的部分,仍然表现良好。

客户端生成sequential guid代码如下

 1    public static class SequentialGuid

 2    {

 3        [DllImport("rpcrt4.dll", SetLastError = true)]

 4        static extern int UuidCreateSequential(out Guid guid);

 5

 6        public static Guid NewGuid()

 7        {

;

 9

            Guid guid;

            int result = UuidCreateSequential(out guid);

            if (result != RPC_S_OK)

            {

                throw new ApplicationException("Create sequential guid failed: " + result);

            }



            return guid;

        }

    }

最新文章

  1. HTMLParser使用
  2. Daily Scrum 12.1
  3. Hadoop 2.4.1 设置问题小结【原创】
  4. BZOJ-1433 假期的宿舍 最大流+基础建图
  5. 解决Flash和html在多标签浏览器中互访问题
  6. hibernate的oracle配置(转)
  7. php实现自动运行文件
  8. ccf集合竞价
  9. POJ 1456 Supermarket
  10. HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用 php
  11. Fedora下用Iptux,中文乱码解决
  12. OC基础14:使用文件
  13. 号称精通Java的你,是否真的名副其实
  14. springmvc log4j 配置
  15. Visual Studio图形调试器详细使用教程(基于DirectX11)
  16. springboot打包去除资源文件,启动时指定配置文件位置,使用log4j2替换默认logback
  17. 《http权威指南》读书笔记2
  18. Window环境下配置MySQL 5.6的主从复制
  19. 关于EasyUI datagrid 无法在dialog中显示的问题分析及解决方案!
  20. 爬虫之验证码IP攻防心得——小总结

热门文章

  1. 基于 Android NDK 的学习之旅-----HelloWorld
  2. 浏览器对象模型bom的作用是什么?
  3. 三天打渔,俩天晒网(C++实现)
  4. 在TMemo上画一条线(超级简单,举一反三)
  5. 三次握手、四次握手、backlog
  6. Qt的paint函数重写,以及QPaint给一条线绘制箭头
  7. 【BZOJ 1032】 [JSOI2007]祖码Zuma
  8. linux的开机启动过程:
  9. Java:JSON解析工具-org.json
  10. 使用Visual Studio 2010 一步一步创建Powershell Module 和 Cmdlet