システム時間 (Guid.Comb) から GUID を作成する NHibernate の機能に関するブログ記事を読んだところです。これにより、データベースの断片化が大幅に回避されます。これは、SQL Server Sequential ID に相当するクライアント側と呼ぶことができます。
Linq-to-Sql プロジェクトで (コードで Guid を生成することによって) 同様の戦略を使用できる方法はありますか?
システム時間 (Guid.Comb) から GUID を作成する NHibernate の機能に関するブログ記事を読んだところです。これにより、データベースの断片化が大幅に回避されます。これは、SQL Server Sequential ID に相当するクライアント側と呼ぶことができます。
Linq-to-Sql プロジェクトで (コードで Guid を生成することによって) 同様の戦略を使用できる方法はありますか?
C# (セーフ) コード (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);
}
github のソースへのリンク: https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Id/GuidCombGenerator.cs
COMB は次の方法で生成されます。
DECLARE @aGuid UNIQUEIDENTIFIER
SET @aGuid = CAST(CAST(NEWID() AS BINARY(10)) + CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)
これを C# に書き起こすと、次のようになります。
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 );
}
さて、あなたはGuid
手で生成することができます。ただし、aの利点の1つは、Guid
推測できないことです。つまり0000-...-0005
、レコードが与えられた場合、通常、(攻撃者からの)レコードをチェックするポイントはほとんどありません0000-....-0004
。
また-再断片化?このデータに非クラスター化インデックスがある限り、これが問題であるかどうかはわかりません。通常、クラスター化されたインデックスをに配置することはないため、テーブルはヒープになります( intGuid
などの個別のクラスター化されたインデックスがない場合)。IDENTITY
この場合、最後に追加し、新しいGuid
ものを非クラスター化インデックスに挿入します。本当の痛みはありません。
(編集)時間を直接使用することの1つの問題は、衝突のリスクがはるかに高くなることです。タイトループの作成(つまり、いくつかを順番に作成するときに繰り返しを避ける)について心配する必要がありますGuid
。これは、同期などを意味します。複数のマシンが並行して集中的に動作している場合は、さらに厄介になります。重複する可能性があります。 。
UuidCreateSequential はいつでも呼び出すことができます。これは「古い」GUID ジェネレーターです (MSFT が現在使用しているよりランダムなスタイルの GUID に変更した 2000 年より前のようです)。古い UuidCreate の名前を UuidCreateSequential に変更し、新しい GUID ジェネレーターを UuidCreate の新しい実装に配置しました。UuidCreateSequential は、SQL Server が NewSequentialID() で使用するものでもあり、通常の GUID と同じくらい一意ですが、同じプロセスで行にそれらの山を作成すると、それらが連続するという利点があります。
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;
/// <summary>
/// Generate a new sequential GUID. If UuidCreateSequential fails, it will fall back on standard random guids.
/// </summary>
/// <returns>A GUID</returns>
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();
}
}
}
}
@アルル、@ダグ
GUID の最後に時間の部分を入れたのはなぜですか?
先頭のバイトは順序付けにとってより重要であると考えました。順序付けは、インデックスの断片化を防ぐために最初に時間部分が導入された理由です。
OK、私は答えを見つけました.Bernhard Kircherと彼が参照しているサイトComparing GUID and uniqueidentifier Values (ADO.NET)からのこの答え。
したがって、この方法で生成された GUID は、MS SQL-Server 以外のデータベースでは同じようには機能しませんが、これは LINQ-to-SQL とは関係ありません。
変形した URL で申し訳ありませんが、これ以上リンクを投稿するほどの評判がありません。
Doug が最初に Entity Framework モデルで投稿した方法と同様の方法を使用したので、Linq to SQL を使用しても実行できるはずです。
これを行っている間、テスト用のコーム GUID ジェネレーターが必要であり、オンラインでコーム GUID を生成するこの小さなツールを構築することになりました。
http://www.webdesigncompany.co.uk/comb-guid/
うまくいけば、それもあなたを助けるでしょう。