理解 newid ()和 newsequentialid ()

参考引用: https://blog.csdn.net/xushichang/article/details/4390957

UNIQUEIDENTIFIER类型: 使用newid()、 newsequentialid()

  1. newsequentialid 函数比起 newid 函数最大的好处是:如果你在一个 UNIQUEIDENTIFIER 字段上建立索引,使用 newid 产生的新的值是不固定的,所以新的值导致索引B+树的变化是随机的。而 newsequentialid 产生的新的值是有规律的,则索引B+树的变化是有规律的。有规律和无规律就会带来性能的改进。

  2. UNIQUEIDENTIFIER做主键(Primary Key)是一件很方便的事情,在数据合并等操作中有不可替代的优势
    但是由于普通的GUID的分散性使得如果主键加上聚集索引(Clustered Index)会导致在插入记录时效率大大降低

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

在指定计算机上创建大于先前通过该函数生成的任何 GUID 的 GUID。
newsequentialid() 不能在查询中引用。
注:即只能做为数据库列的DEFAULT VALUE,不能执行类似Select newsequentialid()的语句
只有当计算机没有网卡时,newsequentialid() 生成的 GUID 才在该特定计算机中是唯一的。
注:这句话是错误的,应该是只有只有当计算机有网卡时,生成的GUID才是全球唯一
您可以使用 newsequentialid() 生成 GUID 以减少叶级别索引上的页争用。

使用例子:

create table #dd
(
	fid uniqueidentifier NULL  DEFAULT (NEWSEQUENTIALID()),
 	fname [nvarchar](20)
)
insert into #dd(fname)values('dddff') 

select * from #dd where fid > 'D8407C7D-0E7C-DE11-94B0-001A4DDD5F17' and fid<'E2507993-0E7C-DE11-94B0-001A4DDD5F17'

但是使用 newsequentialid() 却不是那么一帆风顺

1. 如何获得生成的GUID

如果生成的GUID所在字段做为外键要被其他表使用,我们就需要得到这个生成的值
通常,PrimaryKey是一个IDENTITY字段,我们可以在INSERT之后执行 SELECT SCOPE_IDENTITY()来获得新生成的ID
但是由于 newsequentialid() 不是一个INDETITY类型,这个办法是做不到了,而他本身又只能在默认值中使用,不可以事先SELECT好再插入,那么我们如何得到呢?有以下两种方法:

–测试表

CREATE TABLE TABLE1(ID uniqueidentifier default newsequentialid(), col1 nvarchar(20), col2 nvarchar(20))

–1.1 定义临时表变量


DECLARE @outputTable TABLE(ID uniqueidentifier) 
INSERT INTO TABLE1(col1, col2) 
OUTPUT INSERTED.ID INTO @outputTable
VALUES('value1', 'value2') 
SELECT ID FROM @outputTable 

–2.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语句来建表。 (2008没有该问题)

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

我建立了一个表有ID和TIMESTAMP两个字段,用newsequentialid()和客户端两种方法生成记录,并按ID和TIMESTAMP两种方式进行排序。
newsequentialid()版本的结果永远一样。而客户端生成就有一些问题,如果连续运行程序,表现良好,如果间隔一段时间后继续运行,新生成的记录就不一定大于之前生成的记录,而每次间隔之间连续运行的部分,仍然表现良好。
客户端生成sequential guid代码如下

public static class SequentialGuid
{
    [DllImport("rpcrt4.dll", SetLastError = true)]
    static extern int UuidCreateSequential(out Guid guid);

    public static Guid NewGuid()
    {
        const int RPC_S_OK = 0;

        Guid guid;
        int result = UuidCreateSequential(out guid);
        if (result != RPC_S_OK)
       {
            throw new ApplicationException("Create sequential guid failed: " + result);
        }

        return guid;
    }
}

本人另一篇文章提供另一个方法也能产生有序的GUID,而不会有上述问题:

详见:https://blog.csdn.net/carcarrot/article/details/138272417


    public class GuidEx
    {
        /// <summary>
        /// 产生有序的GUID (用于解决默认无序的GUID给数据库聚集索引字段造成的性能问题)
        /// </summary>
        /// <returns></returns>
        public static string GenerateOrderly(int index = 0)
        {
            byte[] guidArray = Guid.NewGuid().ToByteArray();
 
            DateTime baseDate = new DateTime(1900, 1, 1);
            DateTime now = DateTime.Now;
 
            TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);
 
            TimeSpan msecs = new TimeSpan(now.Ticks - (new DateTime(now.Year, now.Month, now.Day).Ticks));
            byte[] daysArray = BitConverter.GetBytes(days.Days);
            byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds + index));
 
            Array.Copy(daysArray, 0, guidArray, 2, 2);
            //毫秒高位
            Array.Copy(msecsArray, 2, guidArray, 0, 2);
            //毫秒低位
            Array.Copy(msecsArray, 0, guidArray, 4, 2);
            return new Guid(guidArray).ToString();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值