`
wyf
  • 浏览: 424971 次
  • 性别: Icon_minigender_1
  • 来自: 唐山
社区版块
存档分类
最新评论

C#生成唯一值的方法

 
阅读更多

使用1、MaxId表存储各表的MaxId

 

专门一个数据库,记录各个表的MaxId值,建一个存储过程来取Id,逻辑大致为:开启事物,对于在表中不存在记录,直接返回一个默认值为1的键值,同时插入该条记录到table_key表中。而对于已存在的记录,key值直接在原来的key基础上加1更新到MaxId表中并返回key

第一步:创建表
create table table_key
(
       table_name   varchar(50) not null primary key,
       key_value    int         not null
)


第二步:创建存储过程来取自增ID
create procedure up_get_table_key
(
   @table_name     varchar(50),
   @key_value      int output
)
as
begin
     begin tran
         declare @key  int
         
         --initialize the key with 1
         set @key=1
         --whether the specified table is exist
         if not exists(select table_name from table_key where table_name=@table_name)
            begin
              insert into table_key values(@table_name,@key)        --default key vlaue:1
            end
         -- step increase
         else    
            begin
                select @key=key_value from table_key with (nolock) where table_name=@table_name
                set @key=@key+1
                --update the key value by table name
                update table_key set key_value=@key where table_name=@table_name
            end
        --set ouput value
    set @key_value=@key

    --commit tran
    commit tran
        if @@error>0
      rollback tran
end

 存储过程中不使用事物,一旦使用到事物性能就急剧下滑。直接使用UPDATE获取到的更新锁,即SQL SERVER会保证UPDATE的顺序执行。(已在用户过千万的并发系统中使用)

create procedure [dbo].[up_get_table_key]
(
   @table_name     varchar(50),
   @key_value      int output
)
as
begin

	SET NOCOUNT ON;
	DECLARE @maxId INT
	UPDATE table_key
	SET @maxId = key_value,key_value = key_value + 1 
	WHERE table_name=@table_name
	SELECT @maxId

end

 结论:适用中型应用,此方案解决了分表,关联表插入记录的问题。但是无法满足高并发性能要求。同时也存在单点问题,如果这个数据库cash掉的话……

我们目前正头痛这个问题,因为我们的高并发常常出现数据库访问超时,瓶颈就在这个MaxId表。我们也有考虑使用分布式缓存(egmemcached)缓存第一次访问MaxId表数据,以提高再次访问速度,并定时用缓存数据更新一次MaxId表,但我们担心的问题是:

a)         倘若缓存失效或暴掉了,那缓存的MaxId没有更新到数据库导致数据丢失,必须停掉站点来执行Select max(id)各个表来同步MaxId表。

b)         分布式缓存不是一保存下去,其他服务器上就立马可以获取到的,即数据存在不确定性。(其实也是缓存的一个误用,缓存应该用来存的是频繁访问并且很少改动的内容)

         改进方案:

整体思想:建立两台以上的数据库ID生成服务器,每个服务器都有一张记录各表当前IDMaxId表,但是MaxId表中Id的增长步长是服务器的数量,起始值依次错开,这样相当于把ID的生成散列到每个服务器节点上。例如:如果我们设置两台数据库ID生成服务器,那么就让一台的MaxId表的Id起始值为1(或当前最大Id+1),每次增长步长为2,另一台的MaxId表的ID起始值为2(或当前最大Id+2),每次步长也为2。这样就将产生ID的压力均匀分散到两台服务器上,同时配合应用程序控制,当一个服务器失效后,系统能自动切换到另一个服务器上获取ID,从而解决的单点问题保证了系统的容错。(Flickr思想)

但是要注意:1、多服务器就必须面临负载均衡的问题;2、倘若添加新节点,需要对原有数据重新根据步长计算迁移数据。

结论:适合大型应用,生成Id较短,友好性比较好。(强烈推荐)

2、COMB数据类型的基本设计思路是这样的:既然GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么能不能通过组合的方式,保留GUID10个字节,用另6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与GUID组合起来,在保留GUID的唯一性的同时增加了有序性,以此来提高索引效率。

NHibernate中,COMB型主键的生成代码如下所示:

/// <summary> /// Generate a new <see cref="Guid"/> using the comb algorithm. 
        /// </summary> 
        private Guid GenerateComb()
        {
            byte[] guidArray = Guid.NewGuid().ToByteArray();

            DateTime baseDate = new DateTime(1900, 1, 1);
            DateTime now = DateTime.Now;

            // Get the days and milliseconds which will be used to build    
            //the byte string    
            TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);
            TimeSpan msecs = now.TimeOfDay;

            // Convert to a byte array        
            // Note that SQL Server is accurate to 1/300th of a    
            // millisecond so we divide by 3.333333    
            byte[] daysArray = BitConverter.GetBytes(days.Days);
            byte[] msecsArray = BitConverter.GetBytes((long)
              (msecs.TotalMilliseconds / 3.333333));

            // Reverse the bytes to match SQL Servers ordering    
            Array.Reverse(daysArray);
            Array.Reverse(msecsArray);

            // Copy the bytes into the guid    
            Array.Copy(daysArray, daysArray.Length - 2, guidArray,
              guidArray.Length - 6, 2);
            Array.Copy(msecsArray, msecsArray.Length - 4, guidArray,
              guidArray.Length - 4, 4);

            return new Guid(guidArray);
        }

 结论:适合大型应用。即保留GUID的唯一性的同时增加了GUID有序性,提高了索引效率;解决了关联表业务问题;生成的Id不够友好;占据了32位。(强烈推荐)

3、自己写编码规则

优点:全局唯一Id,符合业务后续长远的发展(可能具体业务需要自己的编码规则等等)。

缺陷:根据具体编码规则实现而不同;还要考虑倘若主键在业务上允许改变的,会带来外键同步的麻烦。

我这边写两个编码规则方案:(可能不唯一,只是个人方案,也请大家提出自己的编码规则

1)         12位年月日时分秒+5位随机码+3位服务器编码  (这样就完全单机完成生成全局唯一编码)---20

缺陷:因为附带随机码,所以编码缺少一定的顺序感。(生成高唯一性随机码的方案稍后给给出程序)

2)         12位年月日时分秒+5位流水码+3位服务器编码 (这样流水码就需要结合数据库和缓存)---20位   (将影响顺序权重大的“流水码”放前面,影响顺序权重小的服务器编码放后)

缺陷:因为使用到流水码,流水码的生成必然会遇到和MaxId、序列表、Sequence方案中类似的问题

(为什么没有毫秒?毫秒也不具备业务可读性,我改用5位随机码、流水码代替,推测1秒内应该不会下99999[五位]条语法)

 

结论:适合大型应用,从业务上来说,有一个规则的编码能体现产品的专业成度。(强烈推荐)

分享到:
评论

相关推荐

    C#生成唯一值的方法汇总

    主要介绍了C#生成唯一值的方法汇总,有需要的朋友可以参考一下

    生成GUID程序,C#源代码,System.Guid.NewGuid().ToString()全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装。在许多流行软件应用程序(例如 Web 浏览器和媒体播放器)中,都使用 GUID。

    生成GUID程序,C#源代码,System.Guid.NewGuid().ToString()全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装。在许多流行软件应用程序(例如 Web 浏览器和媒体播放器)中,都使用 GUID。 GUID...

    C#微软培训资料

    4.1 值 类 型 .28 4.2 引 用 类 型 .33 4.3 装箱和拆箱 .39 4.4 小 结 .42 第五章 变量和常量 .44 5.1 变 量 .44 5.2 常 量 .46 5.3 小 结 .47 第六章 类 型 转 换 .48 6.1 隐式类型转换 .48 6.2...

    微软C#语言规范,C#语言教程中文版

    9.7.1 别名的唯一性 262 10. 类 263 10.1 类声明 263 10.1.1 类修饰符 263 10.1.1.1 抽象类 264 10.1.1.2 密封类 264 10.1.1.3 静态类 264 10.1.2 分部修饰符 265 10.1.3 类型形参 265 10.1.4 类基本规范 266 10.1....

    C#语言规范(2.0,3.0,4.0合集)

    这个是C#语言规范2.0,3.0,4.0的合集,是关于 C# 语法的权威资料。它们包含该语言各个方面的详细信息,包括 Visual C# 产品文档未涉及的许多语法点。 4.0目录 1. 简介 1 1.1 Hello world 1 1.2 程序结构 2 1.3 ...

    风越ASP代码生成器2.8

    08、支持检测提交字符的最小、最大输入长度、是否空值/唯一值、文本类型:★ 不检测 非特殊字符 仅单词字符 仅单词字符空格 仅26个字母 仅中文字符 仅允许整数 仅允许小数 仅日期/时间 仅日期+时间 仅日期 仅时间 ...

    C#编程经验技巧宝典

    115 &lt;br&gt;0193 如何获取应用程序当前执行的路径 116 &lt;br&gt;0194 如何获取当前操作系统的信息 116 &lt;br&gt;0195 如何实现基本数据类型随意转换 116 &lt;br&gt;0196 如何生成全局唯一标识符(GUID) 118 &lt;br&gt;...

    风越.net代码生成器 v3.5

    08、支持检测提交字符的最小、最大输入长度、是否空值/唯一值、文本类型:★ 不检测 非特殊字符 仅单词字符 仅单词字符空格 仅26个字母 仅中文字符 仅允许整数 仅允许小数 仅日期/时间 仅日期+时间 仅日期 仅时间 ...

    风越.Net代码生成器 [FireCode Creator] V1.3 精简版

    08、支持检测提交字符的最小、最大输入长度、是否空值/唯一值、文本类型:★ 不检测 非特殊字符 仅单词字符 仅单词字符空格 仅26个字母 仅中文字符 仅允许整数 仅允许小数 仅日期/时间 仅日期+时间 仅日期 仅时间 ...

    风越asp代码生成器 V3.5

    08、支持检测提交字符的最小、最大输入长度、是否空值/唯一值、文本类型:★ 不检测 非特殊字符 仅单词字符 仅单词字符空格 仅26个字母 仅中文字符 仅允许整数 仅允许小数 仅日期/时间 仅日期+时间 仅日期 仅时间 ...

    C#语言规范4.0

    9.7.1 别名的唯一性 262 10. 类 263 10.1 类声明 263 10.1.1 类修饰符 263 10.1.1.1 抽象类 264 10.1.1.2 密封类 264 10.1.1.3 静态类 264 10.1.2 分部修饰符 265 10.1.3 类型形参 265 10.1.4 类基本规范 266 10.1....

    C#语言规范(4.0版本)

    Microsoft(微软)C#语言规范4.0版本,非常值得大家学习收藏! 目录 1. 简介 1 1.1 Hello world 1 1.2 程序结构 2 1.3 类型和变量 3 1.4 表达式 6 1.5 语句 8 1.6 类和对象 12 1.6.1 成员 12 1.6.2 可访问性 13 1.6.3 ...

    A*算法求解八数码问题_C#语言

    4、 只计算初始节点的h值,其它生成的节点的h值是根据当前状态的h值、移动的操作等计算后得出的,规则如下: a) 采用W(n)这种方式,不在位置的将牌数,共有以下3中情况: i. 该数字原不在最终位置上,移动后,在其...

    C#_语言规范_4.0_中文版

    C# 语言规范 版本 4.0 目录 1. 简介 1 1.1 Hello world 1 1.2 程序结构 2 1.3 类型和变量 3 1.4 表达式 6 1.5 语句 8 1.6 类和对象 12 1.6.1 成员 12 1.6.2 可访问性 13 1.6.3 类型参数 13 1.6.4 基类 14 1.6.5 字段...

    ArcEngine+C#统计图表(柱状图,饼状图)

    ArcEngine基于C#的开发,这次的是统计图表,包括柱状图和饼状图,统计的是某个图层中某个字段的唯一值对比,代码比较简单,参考使用

    风越.net代码生成器v2.9

    08、支持检测提交字符的最小、最大输入长度、是否空值/唯一值、文本类型:★ 不检测 非特殊字符 仅单词字符 仅单词字符空格 仅26个字母 仅中文字符 仅允许整数 仅允许小数 仅日期/时间 仅日期+时间 仅日期 仅时间 ...

Global site tag (gtag.js) - Google Analytics