SQL Serverがuuidを比較する方法
SQL Serverは、.uidとは異なる方法でuuid値をソートします。 比較は、右から左へのバイトグループで実行されます。 バイトグループ内では、比較はすでに左から右に行われています。 (バイトグループは「-」で区切られたシーケンスです。)2つのuuid値を比較する場合、
@ u1 = '206AEBE7-ABF0-47A8-8AA5-6FDDF39B9E4F'
そして
@ u2 = '0F8257A1-B40C-4DA0-8A37-8BBC55183CAE'の場合、出力は@ u2> @ u1になります。前述のように、SQLサーバーは右端のバイトグループ(6FDDF39B9E4F <8BBC55183CAE)から比較を開始するためです。 より技術的に言えば、バイト9から15は降順で、データベース内のuuidソート順序に最大の影響を与えます。
MagnumライブラリでのCombGuidの実装
このプロジェクトでは、 Magnumライブラリを使用します。その一部は、時間制限のあるGUIDを作成する単一のGenerate()メソッドを持つ静的なCombGuidクラスです。 Magnumは、 GitHubでホストされるオープンソースライブラリです。 私はあまり面倒ではなく、Guid作成メソッドの実装がこのライブラリでどのように見えるかを見ました。
public static class CombGuid { static readonly DateTime _baseDate = new DateTime(1900, 1, 1); public static Guid Generate() { byte[] guidArray = Guid.NewGuid().ToByteArray(); DateTime now = DateTime.Now; // Get the days and milliseconds which will be used to build the byte string var days = new TimeSpan(now.Ticks - _baseDate.Ticks); TimeSpan msecs = now.TimeOfDay; // Convert to a byte array // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333 byte[] daysArray = BitConverter.GetBytes(days.Days); byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds/3.333333)); // Reverse the bytes to match SQL Servers ordering Array.Reverse(daysArray); Array.Reverse(msecsArray); // Copy the bytes into the guid Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2); Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4); return new Guid(guidArray); } }
アルゴリズムは非常に簡単です。
9〜10バイトで、1900年1月1日から経過した日数がエンコードされます。
Guid vs CombGuid。 データベースの挿入速度を比較する
最後に、サーバーSQLテーブルにレコードを挿入するコンテキストで、Guid.NewGuid()メソッドによって生成されたuuidが、CombGuid.Generate()を介して作成された兄弟よりも遅いのと比較して、それがすべての目的に達しました。
テストのために、SQLサーバー上にテーブルを作成し、これらのテーブルに100,000行を挿入する2つのスクリプトを作成しました。 最初のスクリプトは、CombGuid.Generate()メソッドを使用して作成されたIDを持つデータベース行に挿入し、2番目のスクリプトはGuid.NewGuid()メソッドを使用して挿入します。
テストスクリプトの一部。
USE [CombIdTest] GO -- DBCC DROPCLEANBUFFERS; DBCC FREEPROCCACHE; CREATE TABLE [dbo].[CombId]( [ID] [uniqueidentifier] NOT NULL, [Value] [varchar](4000) NOT NULL, CONSTRAINT [PK_CombId] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO -- begin transaction insert into CombId Values ('5cb31d3d-3793-428e-beb0-a2e4047e255c','somevalue'); insert into CombId Values ('1e905fa1-e4d4-4a2c-a185-a2e4047e255d','somevalue'); -- 99998 insert commit transaction
挿入を実行する前に、バッファキャッシュがフラッシュされ、トランザクションログへの呼び出し回数を減らすために、挿入自体が1つのトランザクションで実行されます。 各スクリプトは3回実行され、クライアント統計の「合計実行時間」パラメーターが実行時間として使用されました。 測定はMSSQL Server 2012で行われました。
測定結果(ミリ秒単位)。
1 | 2 | 3 | 平均 | |
コンビッド | 2795 | 2882 | 2860 | 2845,667 |
ランダムガイド | 3164 | 3129 | 3111 | 3134,667 |
CombGuidを含むレコードを挿入するスクリプトの利点は、「通常の」uuidを使用したスクリプトに比べて10パーセント強です。 CombGuidを使用すると、テーブルのサイズにもプラスの効果がありました。そのサイズは、ほぼ1.5倍小さく、3.75 MB対5.25 MBでした。
さて、最後にいくつかの質問
データベースの主キーとして何を使用しますか?
uuidまたは類似のバイト構造を使用する場合、どのように生成しますか?