J
Jose_Manuel_Jurado
Today, I worked on a service request that our customer asked about how SQL Server sorts the uniqueidentifier data type. We know that uniqueidentifier store globally unique identifiers (GUIDs). GUIDs are widely used for unique keys due to their extremely low probability of duplication. One common method to generate a GUID in SQL Server is by using the NEWID() function. However, the ordering of GUIDs, especially those generated by NEWID(), can appear non-intuitive. I would like to share my lessons learned how to determine the ordering method using uniqueidentifier and NEWID().
We know that a GUID is a 16-byte value typically represented in a standard format of 32 hexadecimal characters separated by hyphens, for example, EB37F277-8A16-4DE3-B1E3-FFFCBA956A82.
Each section represents different parts of the GUID:
When we generated a NEWID() function generates a random GUID. This randomness ensures uniqueness but can lead to seemingly arbitrary ordering when GUIDs are compared and sorted. The comparison is done byte-by-byte from left to right in lexicographical order.
Consider the following GUIDs generated by NEWID():
To understand how SQL Server orders these GUIDs, we need to break them down into their binary components and compare each part:
When these GUIDs are ordered, SQL Server compares each byte in sequence. The final sorted order is:
To better understand and work with GUIDs, you can create SQL functions that decompose GUIDs into their components and show their ordering. To understand how the GUID is decomposed I would like to share this function.
For example, we have this table and we are going to sort using the [Guid No_] column with NewID().
For example, we have this table and we are going to sort using the sorted calculation column with NewID().
Continue reading...
We know that a GUID is a 16-byte value typically represented in a standard format of 32 hexadecimal characters separated by hyphens, for example, EB37F277-8A16-4DE3-B1E3-FFFCBA956A82.
Each section represents different parts of the GUID:
- The first 8 characters (4 bytes)
- The next 4 characters (2 bytes)
- The following 4 characters (2 bytes)
- The next 4 characters (2 bytes)
- The final 12 characters (6 bytes)
When we generated a NEWID() function generates a random GUID. This randomness ensures uniqueness but can lead to seemingly arbitrary ordering when GUIDs are compared and sorted. The comparison is done byte-by-byte from left to right in lexicographical order.
Consider the following GUIDs generated by NEWID():
- C2EB258A-147F-4F26-97D7-0000F053CCA8
- 6682BC4F-949E-478F-BBA2-0003C71CD035
- A6D423B8-07F3-4F13-B34E-0004DC3317B7
- EE2C394E-7AB0-468F-B959-0005C0CC598D
How the ordering works:
To understand how SQL Server orders these GUIDs, we need to break them down into their binary components and compare each part:
C2EB258A-147F-4F26-97D7-0000F053CCA8
- Binary: C2 EB 25 8A 14 7F 4F 26 97 D7 00 00 F0 53 CC A8
6682BC4F-949E-478F-BBA2-0003C71CD035
- Binary: 66 82 BC 4F 94 9E 47 8F BB A2 00 03 C7 1C D0 35
A6D423B8-07F3-4F13-B34E-0004DC3317B7
- Binary: A6 D4 23 B8 07 F3 4F 13 B3 4E 00 04 DC 33 17 B7
EE2C394E-7AB0-468F-B959-0005C0CC598D
- Binary: EE 2C 39 4E 7A B0 46 8F B9 59 00 05 C0 CC 59 8D
When these GUIDs are ordered, SQL Server compares each byte in sequence. The final sorted order is:
- 6682BC4F-949E-478F-BBA2-0003C71CD035
- A6D423B8-07F3-4F13-B34E-0004DC3317B7
- C2EB258A-147F-4F26-97D7-0000F053CCA8
- EE2C394E-7AB0-468F-B959-0005C0CC598D
To better understand and work with GUIDs, you can create SQL functions that decompose GUIDs into their components and show their ordering. To understand how the GUID is decomposed I would like to share this function.
Code:
CREATE FUNCTION dbo.DescomponerGUIDString (@guid UNIQUEIDENTIFIER)
RETURNS NVARCHAR(100)
AS
BEGIN
DECLARE @part1 NVARCHAR(8) = CONVERT(NVARCHAR(8), SUBSTRING(CONVERT(BINARY(16), @guid), 1, 4), 2);
DECLARE @part2 NVARCHAR(4) = CONVERT(NVARCHAR(4), SUBSTRING(CONVERT(BINARY(16), @guid), 5, 2), 2);
DECLARE @part3 NVARCHAR(4) = CONVERT(NVARCHAR(4), SUBSTRING(CONVERT(BINARY(16), @guid), 7, 2), 2);
DECLARE @part4 NVARCHAR(4) = CONVERT(NVARCHAR(4), SUBSTRING(CONVERT(BINARY(16), @guid), 9, 2), 2);
DECLARE @part5 NVARCHAR(12) = CONVERT(NVARCHAR(12), SUBSTRING(CONVERT(BINARY(16), @guid), 11, 6), 2);
RETURN @part1 + '-' + @part2 + '-' + @part3 + '-' + @part4 + '-' + @part5;
END;
For example, we have this table and we are going to sort using the [Guid No_] column with NewID().
Code:
select [GUID No_], dbo.DescomponerGUIDString([GUID No_]) as x from dbo.ExampleTable
ORDER BY 1
For example, we have this table and we are going to sort using the sorted calculation column with NewID().
Code:
select [GUID No_], dbo.DescomponerGUIDString([GUID No_]) as x from dbo.ExampleTable
ORDER BY 2
Continue reading...