Wednesday, March 9, 2011

Enter the ‘Ordered’ Guid

So in the previous post, I talked about the desire for something with the uniqueness of Guids with the ordered-ness of integers.

Microsoft already have something like this in the database from SQL Server 2005 onwards, but in my mind, this takes manifests the worst aspects of both integer and Guid primary keys.


For starters, NEWSEQUENTIALID() is a database function, which implies that the database generates the id for you – which makes it functionally equivalent to an auto-incremented integer, with the added cost of the Guid’s size.


The true strength of the random Guid is that the id is predictably unique before the insert operation – so that sets of related rows can be inserted directly.


So taking a leaf out of that book, I decided to write a predictably unique Guid, which is also ordered, and reasonably quick to create.


General Principle


The following constructor for Guid seems like a good staring point:

public Guid(int a, short b, short c, byte[] d)

We could somehow configure



  • a to be a (random number) to represent a realm or domain
  • b to be a (random number) to represent a server in that domain
  • c to be a (random number) to represent an application on that server

and then provide a monotonically increasing 64-bit value for d, and we would be in business.


The Guid could be self-constructed external to the database, be predictably unique, and be ordered as well.


Setting up the Context Arguments


I created a new Class Library for this OrderedGuid class.


I used the Settings tab to create three parameters along with some default values. These values will persist after any changes made by making changes to the Class Library’s app.config file.


Settings


In the static constructor of the OrderedGuid class, set up the parameters with random values.

public static class OrderedGuid
{
private static int _a;
private static short _b;
private static short _c;

private static readonly object LockObject = new object();

static OrderedGuid()
{
lock(LockObject)
{
var randomNumberGenerator = new Random();

_a = (int) Settings.Default.Realm_UniqueID;
while (_a == 0)
{
_a = randomNumberGenerator.Next();
}

_b = (short) Settings.Default.Server_UniqueID;
while (_b == 0)
{
_b = (short) randomNumberGenerator.Next(short.MaxValue);
}

_c = (short) Settings.Default.Application_UniqueID;
while (_c == 0)
{
_c = (short) randomNumberGenerator.Next(short.MaxValue);
}
}
}

public static Guid NewSequentialGuid()
{
throw new NotImplementedException();
}
}
We’ll discuss and refine the NewSequentialGuid() implementation shortly. Stay tuned…