UNIQUEIDENTIFIERの代わりにBINARY(16)を使用するとペナルティがありますか?


19

最近、GUIDを保存するBINARY(16)代わりにUNIQUEIDENTIFIERを使用するSQL Serverデータベースを継承しました。主キーを含むすべてに対してこれを行います。

心配する必要がありますか?


一貫してbinary(16)を使用していますか?変数とパラメーターを含めますか?そうでない場合は、暗黙的なキャストの効果を考慮する必要があります。
マーティンスミス

はい、ありがたいことに、暗黙のキャストも処理する必要はありません。
ジョナサンアレン

回答:


21

心配する必要がありますか?

さて、ここには少し気になる点がいくつかあります。

最初: a UNIQUEIDENTIFIER(つまりGuid)が16バイトのバイナリ値であることは事実ですが、

  1. すべてのデータはバイナリ形式INTで保存できます(たとえばBINARY(4)DATETIMEに保存できますBINARY(8)、などに保存できます)。したがって、#2↴
  2. GUIDに別のデータ型を用意するのは、おそらく便利さ以外の理由(おそらくsysnameのエイリアスとしてNVARCHAR(128))があるのでしょう。

私が見つけることができる3つの行動の違いは次のとおりです。

  • UNIQUEIDENTIFIERSQL Serverでの値の比較は、良くも悪くも、実際にはBINARY(16)値の比較と同じ方法では行われません。GUIDとuniqueidentifierの値の比較に関するMSDNページによると、UNIQUEIDENTIFIERSQL Serverの値を比較する場合:

    値の最後の6バイトが最も重要です

  • これらの値は頻繁にはソートされませんが、これら2つのタイプにはわずかな違いがあります。uniqueidentifierのMSDNページによると:

    順序付けは、2つの値のビットパターンを比較することによって実装されません。

  • SQL Serverと.NET(上記の「GUIDとuniqueidentifierの値の比較」ページに記載)でGUID値の処理方法に違いがあるため、このデータをSQL Serverからアプリコードに引き出すことは、 SQL Server比較動作をエミュレートする必要がある場合は、アプリコード。その動作はに変換することでエミュレートできますSqlGuidが、開発者はそれを行うことを知っていますか?

第二:次のステートメントに基づいて

主キーを含むすべてに対してこれを行います。

PKとして、INTまたはBIGINTPKとしても使用すると共に、代替キーとしてではなくPKとしてGUIDを使用することにより、システムパフォーマンスについて一般的に心配します。また、これらのGUID PKがクラスター化インデックスである場合はさらに懸念されます。

更新

OPが@Robの回答に対して行った以下のコメントは、追加の懸念をもたらします。

MySQLから移行された

GUIDは、2つの異なるバイナリ形式で保存できます。そのため、以下に応じて懸念の原因となる可能性があります。

  1. バイナリ表現が生成されたシステム、および
  2. 文字列値が元のシステムの外部(アプリコードなど)で使用された場合、またはインポートファイルなどで使用するためにクライアントに与えられた場合

バイナリ表現が生成された場所に関する問題は、4つの「フィールド」のうち最初の3つのバイト順序に関係しています。上記のWikipediaの記事へのリンクをたどると、RFC 4122が4つのフィールドすべてに対して「ビッグエンディアン」エンコーディングを使用するように指定しているが、Microsoft GUIDは「ネイティブ」エンディアンを使用するように指定していることがわかります。さて、Intelアーキテクチャはリトルエンディアンです。したがって、最初の3つのフィールドのバイト順は、RFC(およびビッグエンディアンシステムで生成されたMicrosoftスタイルのGUID)に準拠したシステムとは逆になります。最初のフィールド「データ1」は4バイトです。あるエンディアンでは、(仮に)として表され0x01020304ます。しかし、他のエンディアンネスではそうなります0x04030201。したがって、現在のデータベースBINARY(16)そのバイナリ表現はRFCに従ってシステムで生成され、現在BINARY(16)フィールドにあるデータをに変換すると、UNIQUEIDENTIFIER最初に作成されたものとは異なるGUIDになります。これは本当に問題ないのIF値は、データベースを残していない、決しておよび値がしかの平等ではなく秩序のために比較されます。

順序付けの問題は、単にに変換しUNIQUEIDENTIFIERた後、順序が同じにならないことです。幸いなことに、元のシステムが実際にMySQLであった場合、MySQLにはUUIDの文字列表現のみがあるため、そもそもバイナリ表現で順序付けは行われませんでした。

バイナリ表現がWindows / SQL Serverの外部で生成された場合、データベースの外部で使用されている文字列値に関する懸念は、より深刻です。バイトの順序が異なる可能性があるため、文字列形式の同じGUIDは、変換が行われた場所に応じて、2つの異なるバイナリ表現になります。アプリケーションコードまたは顧客のように文字列形式でGUIDを与えられた場合ABCのバイナリ形式から来る123 RFCを次のシステムで生成されたバイナリ表現、同じバイナリ表現(すなわちこと123)の文字列形式に変換することになるDEFに変換されたときA UNIQUEIDENTIFIER。同様に、の元の文字列形式はABC456に変換されるときにのバイナリ形式に変換されますUNIQUEIDENTIFIER

したがって、GUIDがデータベースを離れることがない場合、順序付け以外のことをあまり気にする必要はありません。または、MySQLからのインポートが文字列形式(つまりFCCEC3D8-22A0-4C8A-BF35-EC18227C9F40)の変換によって行われた場合、それは問題ない可能性があります。それ以外の場合、それらのGUIDが顧客またはアプリコードで与えられた場合、それらを取得して変換することで、どのように変換されるかをテストしてSELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');、期待されるレコードが見つかるかどうかを確認できます。レコードを照合できない場合は、フィールドをとして保持する必要がありますBINARY(16)

おそらく問題は発生しませんが、適切な条件下では問題が発生する可能性があるため、これについて言及しています。

とにかく新しいGUIDはどのように挿入されますか?アプリコードで生成されましたか?

更新2

別のシステムで生成されたGUIDのバイナリ表現のインポートに関連する潜在的な問題の以前の説明が少し(または多く)混乱している場合は、以下が少し明確になることを願っています。

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String], CONVERT(BINARY(16), @GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
--          BE23ED5F-2CE5-EE40-8F45-49664C9472FD

上記の出力では、「String」と「Binary」の値は同じGUIDからのものです。「Binary」行の下の値は「Binary」行と同じ値ですが、「String」行と同じスタイルでフォーマットされています(つまり、「0x」を削除して4つのダッシュを追加します)。最初の値と3番目の値を比較すると、それらはまったく同じではありませんが、非常に近いものです。右端の2つのセクションは同じですが、左端の3つのセクションは同じではありません。しかし、よく見ると、3つのセクションのそれぞれで同じバイトであり、順序が異なっていることがわかります。最初の3つのセクションのみを表示し、バイトに番号を付けると、2つの表現の間で順序がどのように異なるかがわかりやすくなります。

文字列= 1 5F 2 ED 3 23 4 BE 5 E5 6 2C 7 40 8 EE
バイナリ= 4 BE 3 23 2 ED 1 5F 6 2C 5 E5 8 EE 7 40(Windows / SQL Serverの場合)

したがって、各グループ内では、バイトの順序が逆になりますが、Windows内およびSQL Server内のみです。ただし、RFCに準拠しているシステムでは、バイト順序の反転がないため、バイナリ表現はスティング表現をミラーリングします。

データはどのようにMySQLからSQL Serverに取り込まれましたか?いくつかの選択肢があります。

SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
       CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
    CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));

戻り値:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

バイナリからバイナリへの変換(上記の#2の変換)であると仮定すると、結果のGUIDは、実際UNIQUEIDENTIFIERに変換された場合、次のようになります。

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

戻り値:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

それは間違っています。そしてそれは3つの質問を残します:

  1. データはどのようにSQL Serverにインポートされましたか?
  2. アプリコードは何語で書かれていますか?
  3. アプリコードはどのプラットフォームで実行されていますか?

データベースにGUIDが表示されないため、GUIDはアプリケーションで生成されると想定します。
ジョナサンアレン

バイト順に関する説明に完全に従うとは言えませんが、インデックス付けについて考えるようになっています。uniqueidentifierは、バイナリーよりもインデックスの断片化を引き起こす可能性がありますか?
ジョナサンアレン

2
@JonathanAllen別のUPDATEセクションを追加して、うまく説明できることを願っています。いいえ、インデックス作成はそれらの間で異なるべきではありません。
ソロモンラッツキー

「ありがたいことに」、SQL Serverはバリアント1とバリアント2の間で順序を変更しません。ディスクに異なる方法で格納できたとしても、一貫して同じ混乱した順序になります。
user2864740

5

常に心配することができます。;)

システムは、uniqueidentifierをサポートしない他のシステムから移行された可能性があります。知らない妥協点はありますか?

デザイナーはuniqueidentifierタイプについて知らなかったかもしれません。他に知らなかったことは何ですか?

技術的には-それは大きな関心事ではありません。


はい、MySQLから移行されました。そして、はい、たくさんの...興味深いものがあります。
ジョナサンアレン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.