-
Notifications
You must be signed in to change notification settings - Fork 4.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Create method Guid.NewSequentialGuid() #22721
Comments
What is a "sequential Guid"? Do you mean one that uses the machine's MAC address rather than being entirely random? |
Note too that "sequential ids" of any sort have all kinds of problems, mostly dealing with recovery/concurrency scenarios. What sort of problem are you trying to solve here? |
@stephentoub I use Guid (Prefix) + Bytes from DateTime (Ticks) to create a new guid. @Clockwork-Muse currently I use to minimize index fragmentation when using Guids at database table PKs. My class: public static class IdentityGenerator
{
/// <summary>
/// Create new sequential Guid
/// </summary>
/// <returns>Guid</returns>
public static Guid NewSequentialGuid()
{
byte[] uid = Guid.NewGuid().ToByteArray();
byte[] binDate = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
byte[] secuentialGuid = new byte[uid.Length];
secuentialGuid[0] = uid[0];
secuentialGuid[1] = uid[1];
secuentialGuid[2] = uid[2];
secuentialGuid[3] = uid[3];
secuentialGuid[4] = uid[4];
secuentialGuid[5] = uid[5];
secuentialGuid[6] = uid[6];
// set the first part of the 8th byte to '1100' so
// later we'll be able to validate it was generated by us
secuentialGuid[7] = (byte)(0xc0 | (0xf & uid[7]));
// the last 8 bytes are sequential,
// it minimizes index fragmentation
// to a degree as long as there are not a large
// number of Sequential-Guids generated per millisecond
secuentialGuid[9] = binDate[0];
secuentialGuid[8] = binDate[1];
secuentialGuid[15] = binDate[2];
secuentialGuid[14] = binDate[3];
secuentialGuid[13] = binDate[4];
secuentialGuid[12] = binDate[5];
secuentialGuid[11] = binDate[6];
secuentialGuid[10] = binDate[7];
return new Guid(secuentialGuid);
}
} So, I call IdentityGenerator.NewSequentialGuid() to create a new Guid using "sequential" logic... Works fine, but I'm thinking about "NewSequentialGuid" as static member at "root" Guid struct... EDIT: @karelz fixed code block formatting - ```c# instead of just ` (which is for inline code) |
How do you guarantee uniqueness? You have to assume multiple threads, multiple processes, and multiple machines all running this logic at the same time. |
Side note: SQL Server at least can generate unique, sequential ids for you. They even mention using them for index issues. |
MAC addresses and having the sequence system-wide is how the Windows |
I believe "sequential GUIDs" are designed to solve a very specific problem: you want to use GUIDs as a clustered primary key in a database. As such, I think this method might belong in code dealing with databases, but not in the general-purpose |
I agree with @svick it's too especial use and not general-purpose... Tks! |
Another reason is performance, as (in Windows anyway) the sequential algorithm is faster, especially for large batches. |
How I could validate the generation of unique sequential Guids? I made some tests and everything works good... @jnm2 |
@balivo Even across processes and machines? |
@balivo - Note that attempting to validate the individual values is not only problematic, but doomed to failure. It's like trying to validate that |
@Clockwork-Muse uniqueness validation... The sequential-ness its ok for me... And I just use NewSequentialGuid at specific scope. In mobile apps, I create a new Order (SFA, example) and make an API request to save at database. So @jnm2 ask about uniqueness, I don't have a sufficient powerful environment to make 100% test before Universe rest in peace (LoL)... I can upload my validation logic and we can make the test happens! ;) |
@balivo I think for global uniqueness, you need theory, not tests. According to Wikipedia:
Version 4 GUIDs have 122 random bits. If I use the same formula, but with 60 random bits, which is what your That sounds good, until you realize this would mean 50 % probability of collision during every 15 ms interval. To get 50 % probability of collision during a larger interval, say, 10 years, the probability of collision during each interval would have to be much smaller. If I get my math right, it means the probability of collision for each 15 ms interval can be only 2.20 × 10-12. For that probability, you can have only 8720 GUIDs in each 15 ms interval, or 581 GUIDs per millisecond. TLDR: If my calculations are correct, if you generate more than about 500 sequential GUIDs per millisecond, world-wide, then over a 10 year period, you will get a 50 % chance of at least one collision. That might be more than okay for your specific use-case, but I don't think it can be called "globally unique". |
@svick tks... DateTime.UtcNow have a 10ms precision... DateTime.Now is 15ms precision... Sounds good at specific scope... But not for general-purpose. Tks! |
@balivo - Not on Windows on corefx, it's not (I'm unsure where Linux has gone). |
I would have assumed from the name that the proposal was to have Version 1 GUIDs, so if I'd wanted them in Windows-only code I'd use: [DllImport("rpcrt4.dll", SetLastError=true)]
static extern int UuidCreateSequential(out Guid guid); I understand that linux's |
Sequential guids compatible with Sql server implementation:
|
Um, if you're trying to use sequential GUIDs on SQL Server, I'd probably just ask the server to create them. Which would solve the uniqueness/concurrency problem (ie, running the given code from multiple machines is going to result in collisions, which might be costly). Note that generating sequential ids is useful to avoid index fragmentation, and not to provide some ordering of data. Row ids should be considered the same as memory addresses in a regular program, and the actual value considered undefined. Never rely on the id for ordering information, especially if the client is/might be allowed to generate it. Always use an explicit, appropriate value column instead (ie, a Also, we most likely can't use that code, because the author hasn't released the copyright/licensed it to us. |
Thank you for the suggestion, but we don't plan to do anything to expose this. Such functionality could easily be implemented however is desired in a library outside of Guid itself. |
Make a new method to create a sequential Guid.
The text was updated successfully, but these errors were encountered: