关于有序guid 的使用

     上次我博客上,发表一篇有关性能测试的博客. http://www.cnblogs.com/jake1/archive/2013/04/23/3039101.html. 当时有些网友说我那数据量大少,没多少可对比性.其实我当时做的性能测试数据也是10万多的. 做出来的性能.

      为了,获取更准确的数据,于是我数据加到100多万. 然后就感觉插入相当慢,查询和修改 倒不会发现性能上有很大差别.后来一想,才知道,因为我是用guid 作为主键的.所以会出现这种情况. 关于guid和自增id 在现在数据库中是经常使用的.至于他们的优缺点,我就不在这里讨论了. 

      我在这里只想说的是,如果你选择了guid作为你的主键,尤其是你的表数据量比较大的话,要考虑用顺序的guid,这样才能在插入数据上,就会获得比较大的性能提升.关于这这里性能数据,请看我的压力测试结果. 

没有顺序guid的
方法[sqlDB_add           ]: 成功数3940   ,失败数6060   ,完成数10000  ,平均时间19373.24毫秒,[]
方法[sqlDB_add           ]: 成功数7539   ,失败数2461   ,完成数10000  ,平均时间11449.45毫秒,[]
方法[sqlDB_add           ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间3041.29毫秒,[]
方法[sqlDB_add           ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间1867.23毫秒,[]
方法[sqlDB_add           ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间1222.81毫秒,[]
方法[sqlDB_add           ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间452.04 毫秒,[]
方法[sqlDB_add           ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间576.00 毫秒,[]
方法[entityFramework_add ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间2678.54毫秒,[]
方法[entityFramework_add ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间642.82 毫秒,[]
方法[entityFramework_add ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间737.68 毫秒,[]

有顺序guid 的.
方法[sqlDB_add           ]: 成功数10000  ,失败数0      ,完成数10000  ,平均时间22.62  毫秒,[]
方法[sqlDB_add           ]: 成功数10000  ,失败数0      ,完成数10000  ,平均时间4.77   毫秒,[]
方法[sqlDB_add           ]: 成功数10000  ,失败数0      ,完成数10000  ,平均时间25.20  毫秒,[]
方法[entityFramework_add ]: 成功数10000  ,失败数0      ,完成数10000  ,平均时间737.95 毫秒,[]
方法[entityFramework_add ]: 成功数10000  ,失败数0      ,完成数10000  ,平均时间276.65 毫秒,[]
方法[entityFramework_add ]: 成功数10000  ,失败数0      ,完成数10000  ,平均时间243.29 毫秒,[]
方法[entityFramework_add ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间169.56 毫秒,[]
方法[entityFramework_add ]: 成功数1000   ,失败数0      ,完成数1000   ,平均时间167.05 毫秒,[]

从测试数据上看,有序guid 的性能上会比没有顺序会快很多.我想这其中的原理,就不用我说了.主要是当用无序的guid 在插入数据时,会产生数据移动,造成性能上会有一定的损耗,尤其是数据量越大,损耗就越多.至于为什么 用ef框架在使用有序guid时,会比.net慢好多,我将在下面会做解释.

   让我先说说,怎样做有序的guid,那就是在数据库里的字段里设置默认函数是NEWSEQUENTIALID(),利用NEWSEQUENTIALID()新生成的值大于上一次生成的值,就可实现有序的的id。

    注意: 该函数不能在查询中直接调用,只能在CREATE TABLE 语句或ALTER TABLE  语句中'uniqueidentifier' 类型的列的DEFAULT 表达式中使用。
    eg:
   CREATE TABLE  GUID_SORT_TABLEA( ID  uniqueidentifier  default NEWSEQUENTIALID(), Code1    nvarchar(10), Order1  smallint) GO
   对于已存在的表,利用下面修改表的语句获取
  ALTER TABLE GUID_SORT_TABLEA add CONSTRAINT default1 default(NEWSEQUENTIALID()) for [id]
 
   现在我们可以插入数据试试,   
INSERT INTO  GUID_SORT_TABLEA(Code1,Order1) values ('1-001',1), ('1-002',2), ('2-001',5),  ('2-002',6), ('1-003',3), ('1-004',4); GO
看有序guid出来了.
  
 
至于为什么,用EF框架插入速度会慢那么多,主要是用ef生成的插入语句是这样的.
exec sp_executesql N'declare @generated_keys table([ID] uniqueidentifier)
insert [dbo].[testTable]([MonthlyDataID], [AccountCode], [AccountName], [Amount], [Year], [Month], [Class], [Appendix], [DealerCode], [DataStatus], [Memo], [IsPercent], [UploadStatus], [Status], [CreationUser], [CreationDate], [ModificaitonUser], [ModificationDate])
output inserted.[ID] into @generated_keys
values (@0, null, null, null, @1, @2, null, null, null, null, @3, @4, null, @5, null, null, @6, @7)
select t.[ID]
from @generated_keys as g join [dbo].[BMW_MonthlyDataDetail] as t on g.[ID] = t.[ID]
where @@ROWCOUNT > 0',N'@0 uniqueidentifier,@1 int,@2 int,@3 nvarchar(500),@4 bit,@5 smallint,@6 varchar(50),@7 datetime2(7)',@0='D88C7815-748D-43E5-9599-F37B0CD88CB3',@1=2012,@2=11,@3=N'hsdgsg',@4=1,@5=1,@6='jake',@7='2013-04-26 21:33:45.6696389'

它是先插入数据,然后再连表查出新生成的guid.所以性能上肯定会慢.

在这里我也想补充一点.就是用ef 框架,要使用默认的函数,作为它的id,必须要设置idIdentity 为Identity,.具体设置如图

  好,上面就是我对有序guid的一些研究,希望对家有帮助.

 
posted @ 2013-04-26 21:43  jake强  阅读(2904)  评论(2编辑  收藏  举报