GUID seqüencial no Linq-to-Sql?

Acabei de ler uma postagem no blog sobre a capacidade do NHibernate de criar um GUID a partir da hora do sistema (Guid.Comb), evitando assim uma boa quantidade de fragmentação do database. Você poderia chamá-lo de equivalente no lado do cliente ao ID Sequencial do SQL Server.

Existe uma maneira que eu poderia usar uma estratégia semelhante no meu projeto Linq-to-Sql (gerando o Guid no código)?

COMBs são gerados da seguinte maneira:

DECLARE @aGuid UNIQUEIDENTIFIER SET @aGuid = CAST(CAST(NEWID() AS BINARY(10)) + CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER) 

Que transcrito em C # ficaria assim:

  public static unsafe Guid CombGuid() { Guid guid = Guid.NewGuid(); byte[] bytes = guid.ToByteArray(); long ticks = DateTime.Now.Ticks; fixed( byte* pByte = bytes ) { int* pFirst = (int *)(pByte + 10); short* pNext = (short*)(pByte + 14); *pFirst = (int)(ticks & 0xFFFFFF00); *pNext = (short)ticks; } return new Guid( bytes ); } 

Código C # (seguro) (Cumprimentos do NHibernate Guid Comb Generator)

 Guid GenerateComb() { byte[] destinationArray = Guid.NewGuid().ToByteArray(); DateTime time = new DateTime(0x76c, 1, 1); DateTime now = DateTime.Now; TimeSpan span = new TimeSpan(now.Ticks - time.Ticks); TimeSpan timeOfDay = now.TimeOfDay; byte[] bytes = BitConverter.GetBytes(span.Days); byte[] array = BitConverter.GetBytes((long) (timeOfDay.TotalMilliseconds / 3.333333)); Array.Reverse(bytes); Array.Reverse(array); Array.Copy(bytes, bytes.Length - 2, destinationArray, destinationArray.Length - 6, 2); Array.Copy(array, array.Length - 4, destinationArray, destinationArray.Length - 4, 4); return new Guid(destinationArray); } 

Um link para a fonte no github: https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Id/GuidCombGenerator.cs

Bem, você poderia gerar o Guid manualmente. No entanto, uma das vantagens de um Guid é que não é adivinhado – ou seja, dado o recorde de 0000-...-0005 , normalmente há pouco ponto (de um atacante) verificar o registro de 0000-....-0004 etc .

Também – re fragmentação? Contanto que você tenha um índice não clusterizado nesses dados, não tenho certeza se isso é um problema. Você normalmente não colocaria um índice clusterizado em um Guid , portanto, a tabela será um heap (a menos que você tenha um índice clusterizado separado, como um int IDENTITY ). Nesse caso, você adicionará ao final e inserirá o novo Guid no índice não agrupado. Nenhuma dor real.

(edite) Um problema de usar o tempo diretamente é que você introduz muito mais risco de colisões; você precisaria se preocupar com a criação do Guid (isto é, evitando a repetição ao criar alguns em sequência), o que significa synchronization, etc. – e fica ainda mais problemático se várias máquinas estiverem trabalhando intensamente em paralelo – as chances são de que você duplicatas.

Você sempre pode chamar UuidCreateSequential; este é o ‘antigo’ guid generator (pré-2000-ish quando o MSFT o alterou para os guidões de estilo mais randoms que estamos acostumados hoje). Eles renomearam o antigo UuidCreate para UuidCreateSequential e colocaram seu novo guid generator em uma nova implementação do UuidCreate. UuidCreateSequential também é o que o SQL Server usa em NewSequentialID (), e é tão exclusivo quanto os guias normais, mas com o benefício de que eles são sequenciais se você criar uma pilha deles em uma linha no mesmo processo.

 using System; using System.Runtime.InteropServices; namespace System { public static class GuidEx { [DllImport("rpcrt4.dll", SetLastError = true)] private static extern int UuidCreateSequential(out Guid guid); private const int RPC_S_OK = 0; ///  /// Generate a new sequential GUID. If UuidCreateSequential fails, it will fall back on standard random guids. ///  /// A GUID public static Guid NewSeqGuid() { Guid sequentialGuid; int hResult = UuidCreateSequential(out sequentialGuid); if (hResult == RPC_S_OK) { return sequentialGuid; } else { //couldn't create sequential guid, fall back on random guid return Guid.NewGuid(); } } } } 

@arul, @Doug

Por que você colocou a parte do tempo no final do GUID?

Eu pensei que os bytes principais são mais significativos para a ordem, e a ordem é porque a parte do tempo foi introduzida em primeiro lugar para evitar a fragmentação do índice.

Ok, eu encontrei a resposta , e esta resposta de Bernhard Kircher e o site Comparing GUID e uniqueidentifier Values ​​(ADO.NET) ao qual ele faz referência.

GUIDs gerados dessa maneira não funcionariam da mesma forma em outros bancos de dados que o MS SQL-Server, mas isso não está relacionado ao LINQ-to-SQL.

Desculpe pelos URLs deformados, mas não tenho reputação suficiente para postar mais links.

Usamos um método semelhante ao que Doug postou acima no modelo do Entity Framework primeiro, então você deve ser capaz de fazer isso usando o Linq to SQL também.

Ao fazer isso, precisávamos de um gerador de guia de pente para teste e acabamos construindo essa pequena ferramenta para gerar guias de pente on-line.

http://www.webdesigncompany.co.uk/comb-guid/

Espero que isso ajude você também.