3

このチュートリアルなど、Sql サーバー インデックスに適した Guid を作成する方法については、多くのハウツーがあります。別の一般的な方法は、NHibernate 実装のもの (以下にリスト) です。そのため、そのようなコードのシーケンシャル要件を実際にテストするテスト メソッドを作成するのは楽しいのではないかと考えました。しかし、私は失敗しました-何が良いSQLサーバーシーケンスになるのかわかりません。それらがどのように注文されているかわかりません。

たとえば、シーケンシャル GUID を作成する 2 つの異なる方法がある場合、(速度以外で) どちらが最適かを判断するにはどうすればよいでしょうか? たとえば、時計が 2 分戻された場合 (タイムサーバーの更新など)、シーケンスが突然壊れるという欠点があるように見えますか? しかし、それは Sql サーバー インデックスにとっても問題になるのでしょうか?

このコードを使用して、シーケンシャル Guid を生成します。

public static Guid CombFromArticle()
{
   var randomBytes = Guid.NewGuid().ToByteArray();
   byte[] timestampBytes = BitConverter.GetBytes(DateTime.Now.Ticks / 10000L);

   if (BitConverter.IsLittleEndian)
      Array.Reverse(timestampBytes);

   var guidBytes = new byte[16];

   Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 10);
   Buffer.BlockCopy(timestampBytes, 2, guidBytes, 10, 6);

   return new Guid(guidBytes);
}

public static Guid CombFromNHibernate()
{
  var destinationArray = Guid.NewGuid().ToByteArray();
  var time = new DateTime(0x76c, 1, 1);
  var now = DateTime.Now;
  var span = new TimeSpan(now.Ticks - time.Ticks);
  var timeOfDay = now.TimeOfDay;
  var bytes = BitConverter.GetBytes(span.Days);
  var 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);
}

記事のものはわずかに高速ですが、SQL サーバーに最適なシーケンスを作成するのはどれですか? 100 万件のレコードを入力して断片化を比較することはできましたが、それを適切に検証する方法さえわかりません。いずれにせよ、シーケンスが SQL サーバーによって定義されたシーケンスであることを保証するテスト ケースを作成する方法を理解したいと思います!

また、これら 2 つの実装についてコメントをお願いします。何が他のものよりも優れているのですか?

4

1 に答える 1

0

SQL Server の順次 GUID を生成しました。事前にあまり多くの記事を見たことはありません..それでも、それは健全なようです.

最初のものはシステム関数で生成し (適切なものを取得するため)、次のものは単純にインクリメントします。もちろん、オーバーフローなどを探す必要があります (また、GUID にはいくつかのフィールドがあります)。

それとは別に、考えにくいことは何もありません。2 つの GUID が一意である場合は、それらのシーケンスも一意であり、数百万未満のままである場合。まあ、それは数学です..少なくとも2つのGUIDが一意であるとは限りません.少なくとも長期的には(人類が成長し続ける場合)。したがって、この種のシーケンスを使用することで、おそらく衝突の確率がほぼ 0 からほぼ 0 に増加します (ただし、わずかに増加します)。仮に.. 数学者に聞いてみてください.. それは誕生日問題http://en.wikipedia.org/wiki/Birthday_problemであり、非常識な日数を持っています。

これは C で書かれていますが、より快適な言語に簡単に翻訳できるはずです。特に、wchar を char に変換することについて心配する必要はありません。

GUID guid;
bool bGuidInitialized = false;
void incrGUID()
{
    for (int i = 7; i >= 0; --i)
    {
        ++guid.Data4[i];
        if (guid.Data4[i] != 0)
            return;
    }
    ++guid.Data3;
    if (guid.Data3 != 0)
        return;
    ++guid.Data2;
    if (guid.Data2 != 0)
        return;
    ++guid.Data1;
    if (guid.Data1 != 0)
        return;
}

GenerateGUID(char *chGuid)
{
    if (!bGuidInitialized)
    {
        CoCreateGuid(&guid); 
        bGuidInitialized = true;
    }
    else
        incrGUID();

    WCHAR temp[42];
    StringFromGUID2(guid, temp, 42-1);
    wcstombs(chGuid, &(temp[1]), 42-1);
    chGuid[36] = 0;

    if (!onlyOnceLogGUIDAlreadyDone)
    {
        onlyOnceLogGUIDAlreadyDone = true;
        WR_cTools_LogTime(chGuid);
    }

    return ReturnCode;
}
于 2012-06-27T17:04:32.383 に答える