C#实现SQLSERVER数据库中有序GUID生成(NewSequentialId)

GUID作为数据库主键由于其无序性所以性能不怎么好,SQL Server中有个函数NewSequentialId可以生成有序的GUID,由于在程序中需要用到,就用C#实现了一下,生成的GUID格式基本和SQL Server一致。

程序代码参考了rpcrt4.dll中UuidCreateSequential的实现。

  1     public class GuidHelper
  2     {
  3         private static bool initialised;
  4         private static int count;
  5 
  6         private static long time;
  7         private static long timelast;
  8         private static ushort sequence;
  9 
 10         private static byte[] address; //网卡MAC
 11         private static readonly object locker = new object();
 12         public static Guid NewSequentialId()
 13         {
 14             lock(locker)
 15             {
 16                 if (!initialised)
 17                 {
 18                     timelast = UuidGetSystemTime();
 19                     count = TICKS_PER_CLOCK_TICK;
 20                     Random rand = new Random(1);
 21                     sequence = (ushort)(((rand.Next(1, 32767) & 0xFF) << 8) + rand.Next(1, 32767) & 0xFF);
 22                     sequence &= 0x1FFF;
 23                     address = GetAddressBytes();
 24                     initialised = true;
 25                 }
 26                 while (true)
 27                 {
 28                     time = UuidGetSystemTime();
 29                     if (time > timelast)
 30                     {
 31                         count = 0;
 32                         break;
 33                     }
 34                     if (time < timelast)
 35                     {
 36                         sequence = (ushort)((sequence + 1) & 0x1FFF);
 37                         count = 0;
 38                         break;
 39                     }
 40                     if (count < TICKS_PER_CLOCK_TICK)
 41                     {
 42                         count++;
 43                         break;
 44                     }
 45                 }
 46 
 47                 timelast = time;
 48                 time += count;
 49 
 50                 byte[] guidArray = new byte[16];
 51 
 52                 uint data1 = (uint)(time & 0xffffffff);
 53                 ushort data2 = (ushort)((time >> 32) & 0xffff);
 54                 ushort data3 = (ushort)((time >> 48) & 0x0fff);
 55                 /* This is a version 1 UUID */
 56                 data3 |= (1 << 12);
 57 
 58                 guidArray[3] = (byte)data1;
 59                 guidArray[2] = (byte)(data1 >> 8);
 60                 guidArray[1] = (byte)(data1 >> 16);
 61                 guidArray[0] = (byte)(data1 >> 24);
 62                 guidArray[5] = (byte)data2;
 63                 guidArray[4] = (byte)(data2 >> 8);
 64                 guidArray[7] = (byte)data3;
 65                 guidArray[6] = (byte)(data3 >> 8);
 66                 guidArray[8] = (byte)(sequence & 0xff);
 67                 guidArray[9] = (byte)((sequence & 0x3f00) >> 8);
 68                 guidArray[9] |= 0x80;
 69                 Array.Copy(address, 0, guidArray, 10, 6);
 70 
 71                 return new Guid(guidArray);
 72             }//locker
 73         }//UuidCreateSequential
 74 
 75         private static readonly int TICKS_PER_CLOCK_TICK = 1000;
 76         private static readonly int SECSPERDAY = 86400;
 77         private static readonly int TICKSPERSEC = 10000000;
 78         private static readonly long SECS_15_OCT_1582_TO_1601 = (17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY;
 79         private static readonly long TICKS_15_OCT_1582_TO_1601 = SECS_15_OCT_1582_TO_1601 * TICKSPERSEC;
 80         private static long UuidGetSystemTime()
 81         {
 82             DateTime dt = DateTime.Now;
 83             var ft = dt.ToFileTime();
 84             ft += TICKS_15_OCT_1582_TO_1601;
 85             return ft;
 86         }
 87 
 88         private static byte[] GetAddressBytes()
 89         {
 90             byte[] bytes;
 91             NetworkInterface[] nic = NetworkInterface.GetAllNetworkInterfaces();
 92             if (nic == null || nic.Length < 1)
 93             {
 94                 bytes = new byte[6];
 95                 bytes[0] = 0x01;
 96                 return bytes;
 97             }
 98             bytes = nic[0].GetPhysicalAddress().GetAddressBytes();
 99             return bytes;
100         }
101     }

代码写的比较粗糙,不过功能已经实现,有需要的朋友可以自行优化!

posted @ 2015-11-15 15:33  Huixch  阅读(1258)  评论(2编辑  收藏  举报