加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

使用NEWSEQUENTIALID解决GUID聚集索引问题 SQLServer数据表主键

发布时间:2020-12-12 15:27:39 所属栏目:MsSql教程 来源:网络整理
导读:UNIQUEIDENTIFIER做主键(Primary Key)是一件很方便的事情,在数据合并等操作中有不可替代的优势 但是由于普通的GUID的分散性使得如果主键加上聚集索引(Clustered Index)会导致在插入记录时效率大大降低 SQL SERVER 2005中新增了一个NEWSEQUENTIALID的函数,M

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

????}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读