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        {
 8            const int RPC_S_OK = 0;
 9
10            Guid guid;
11            int result = UuidCreateSequential(out guid);
12            if (result != RPC_S_OK)
13            {
14                throw new ApplicationException("Create sequential guid failed: " + result);
15            }

16
17            return guid;
18        }

19    }
posted on 2007-08-15 15:25 Mirricle 阅读(2057) 评论(15)  编辑 收藏 网摘

  回复  引用    
2007-08-15 15:09 | ee[未注册用户]
我怎么没有遇到你说的这个Bug?
  回复  引用    
2007-08-15 15:33 | ee[未注册用户]
我以前也是英文版啊,好像没这个问题
  回复  引用  查看    
2007-08-15 15:51 | Mirricle      
@ee
只是推理、猜测一下
至少我这有问题,而且也有别人遇到过

  回复  引用  查看    
2007-08-15 17:25 | 江南白衣      
中文版也有这个问题,郁闷
  回复  引用    
2007-08-15 17:26 | 遨游每刻[未注册用户]
哈哈,谢谢,学习了
  回复  引用  查看    
2007-08-15 18:38 | Mirricle      
@江南白衣
不要被我误导,我只是随便猜测一下。因为我这有问题,@ee说他那没问题

  回复  引用  查看    
2007-08-16 12:15 | Mirricle      
会不会是全局设置了什么,忽略这些错误提示?
  回复  引用  查看    
2007-08-16 16:42 | 深蓝      
感谢.值得学习
  回复  引用  查看    
2007-08-16 19:50 | 江南白衣      
2007-08-15 18:38 by Mirricle
@江南白衣
不要被我误导,我只是随便猜测一下。因为我这有问题,@ee说他那没问题
---------------------
哥们,我是自己测试过了,确实跟你说的一样啊。不过这也没什么大不了多,多了一步操作而已:)

  回复  引用    
2007-08-16 22:57 | XP主题[未注册用户]
不错,哦!!!
  回复  引用  查看    
2007-08-21 13:09 | 出走的影子      
为什么不用newid()?
另外加个int型的identity字段,作为Clustered Index不行吗。干吗一定要放在guid上。

  回复  引用  查看    
2007-08-21 13:14 | Mirricle      
因为需要GUID做主键,使用起来方便,合并数据什么都不用操心。
你添加个INT型的,查询你准备用哪个?用INT?那要GUID干吗,如果用GUID,显然普通索引没有聚集索引快。

  回复  引用  查看    
2008-12-15 21:28 | dudu      
应该是:
DECLARE @outputTable TABLE(ID uniqueidentifier)

文中的代码多了一个逗号。




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 856726




相关文章:

相关链接: