web-dev-qa-db-ja.com

いつUUIDを設計の一部として使用することを本当に強制されますか?

[〜#〜] uuid [〜#〜] のポイントが実際にはわかりません。衝突の確率は実質的にnilですが、実質的にnil不可能に近いことすらありません。

誰かがUUIDを使用する以外に選択肢がない場合の例を挙げることができますか?私が見たすべての用途から、UUIDのない代替設計を見ることができます。確かに設計はもう少し複雑かもしれませんが、少なくともゼロ以外の確率で失敗することはありません。

UUIDは私にとってグローバル変数のような匂いがします。グローバル変数を使用して簡単な設計を実現する方法は数多くありますが、その設計は怠laです。

113
Pyrolistical

RubyのUUIDジェネレーター/パーサーを作成したので、このテーマについては十分な知識があると思います。 4つの主要なUUIDバージョンがあります。

バージョン4のUUIDは、本質的に、暗号的に安全な乱数ジェネレーターから取得した16バイトのランダム性であり、UUIDのバージョンとバリアントを識別するためのビット調整がいくつかあります。これらは衝突する可能性は非常に低いですが、PRNGが使用されている場合、または偶然に本当に、本当に、本当に、本当に、本当に不運が起こった場合に起こる可能性があります。

バージョン5およびバージョン3のUUIDは、それぞれSHA1およびMD5ハッシュ関数を使用して、名前空間をすでに一意のデータと組み合わせてUUIDを生成します。これにより、たとえば、URLからUUIDを生成できます。ここでの衝突は、基礎となるハッシュ関数にも衝突がある場合にのみ可能です。

バージョン1 UUIDが最も一般的です。ネットワークカードのMACアドレス(スプーフィングされていない限り一意である必要があります)、タイムスタンプ、および通常のビット調整を使用してUUIDを生成します。 MACアドレスを持たないマシンの場合、6ノードバイトは暗号的に安全な乱数ジェネレーターで生成されます。タイムスタンプが前のUUIDと一致するほど速く2つのUUIDが順番に生成される場合、タイムスタンプは1ずつ増加します。次のいずれかが発生しない限り、衝突は発生しません。 2つの異なるUUID生成アプリケーションを実行している1台のマシンは、まったく同じ瞬間にUUIDを生成します。ネットワークカードを持たない、またはMACアドレスへのユーザーレベルアクセスのない2台のマシンには、同じランダムノードシーケンスが与えられ、まったく同時にUUIDを生成します。タイムスタンプを表すためにバイトを使い果たし、ゼロにロールバックします。

現実には、これらのイベントはいずれも、単一のアプリケーションのIDスペース内で偶然に発生することはありません。たとえば、インターネット全体の規模でIDを受け入れる場合、またはIDの衝突の場合に悪意のある個人が何か悪いことをする可能性がある信頼できない環境でIDを受け入れている場合を除き、心配する必要はありません。私と同じバージョン4 UUIDを生成する場合、ほとんどの場合、問題ではないことを理解することが重要です。私はあなたのものとは全く異なるIDスペースでIDを生成しました。私のアプリケーションは衝突について決して知らないので、衝突は問題ではありません。率直に言って、悪意のあるアクターのない単一のアプリケーションスペースでは、衝突が発生するずっと前に、バージョン4 UUIDでさえ、毎秒かなりのUUIDを生成していても、地球上のすべての生命の絶滅が起こります。

また、2 ^ 64 * 16は256エクサバイトです。同様に、単一のアプリケーションスペースでIDの衝突が50%発生する前に、256エクサバイト相当のIDを保存する必要があります。

583
Bob Aman

UUIDを購入するのは非常に困難で、一意の識別子を取得することです中央当局と相談したり調整したりする必要なし。何らかの管理されたインフラストラクチャなしでそのようなものを取得できるという一般的な問題は、UUIDが解決する問題です。

誕生日のパラドックスによれば、2 ^ 64 UUIDが生成されるとUUIDの衝突が発生する可能性は50%であると読みました。 2 ^ 64は非常に大きな数値ですが、衝突の50%の可能性は非常にリスクが高いようです(たとえば、衝突の5%の可能性がある前にいくつのUUIDが存在する必要があるか-可能性が大きすぎると思われる場合でも) 。

この分析の問題は2つあります。

  1. UUIDは完全にランダムではありません-時間および/または場所ベースのUUIDの主要なコンポーネントがあります。そのため、衝突が実際に発生する可能性があるため、衝突するUUIDは異なるUUIDジェネレーターからまったく同時に生成される必要があります。いくつかのUUIDが同時に生成される可能性は十分にありますが、この非常に小さなUUIDのセットの衝突の可能性をほとんど不可能にするのに十分な他のネバネバ(位置情報またはランダムビットを含む)があります。

  2. 厳密に言えば、UUIDは、比較される他のUUIDのセット間で一意である必要があるだけです。データベースキーとして使用するUUIDを生成する場合、悪意のある代替ユニバースのどこかで同じUUIDがCOMインターフェイスを識別するために使用されているかどうかは関係ありません。 Alpha-Centauriに「Michael Burr」という名前の誰か(または何か)がいれば混乱しないように。

67
Michael Burr

すべてにゼロ以外の障害の可能性があります。私は、UUIDの衝突よりもはるかに多くの問題(つまり、考えられるほとんどすべて)が発生する可能性に集中します。

30
DanSingerman

「合理的に」、またはあなたが言うように「効果的に」に重点を置いている:十分に現実の世界が機能する方法です。 「実質的に一意」と「真に一意」の間のギャップをカバーするために必要な計算作業の量は膨大です。一意性は、収益が減少する曲線です。その曲線のある時点で、「十分に一意」がまだ手頃な価格の間に線があり、それから非常に急に曲線を描きます。一意性を追加するコストは非常に大きくなります。無限の一意性には無限のコストがかかります。

UUID/GUIDは、比較的言えば、合理的に普遍的に一意であると想定できるIDを生成するための計算上迅速で簡単な方法です。これは、以前に接続されていないシステムからのデータを統合する必要がある多くのシステムで非常に重要です。たとえば、2つの異なるプラットフォームで実行されるコンテンツ管理システムがあり、ある時点で一方のシステムから他方のシステムにコンテンツをインポートする必要がある場合。 IDを変更したくないため、システムAからのデータ間の参照はそのまま残りますが、システムBで作成されたデータとの衝突は望ましくありません。UUIDがこれを解決します。

16
Rex M

UUIDを作成することは絶対に必要ではありません。ただし、offlineユーザーが衝突の可能性が非常に低い何かへのキーをそれぞれ生成できる標準があると便利です。

これは、データベース複製の解決などに役立ちます...

オンラインのユーザーは、オーバーヘッドや衝突の可能性なしで何かの一意のキーを生成するのは簡単ですが、それはUUIDの目的ではありません。

とにかく、ウィキペディアから取られた衝突の可能性に関する言葉:

これらの数値を概観すると、met石に襲われる年間リスクは170億回に1回であると推定されます。これは、1年で数十兆UUIDを作成し、1回重複する確率に相当します。つまり、次の100年間にわたって毎秒10億UUIDを生成した後にのみ、1つの複製が作成される可能性は約50%になります。

14
John Gietzen

また、体の中のすべての粒子が同時に座っている椅子をトンネリングして、突然床に座っていることに気付く可能性はゼロではありません。

心配ですか?

12
user21714

典型的な例は、2つのデータベース間で複製する場合です。

DB(A)はint ID 10のレコードを挿入し、同時にDB(B)はID 10のレコードを作成します。これは衝突です。

UUIDでは、一致しないため、これは起こりません。 (ほぼ確実)

11
Johnno Nolan

UUIDを回避するためのスキームがあります。サーバーをどこかにセットアップして、それがあれば、ソフトウェアの一部が普遍的に一意の識別子を必要とするたびに、彼らはそのサーバーに接続してそれを配布します。シンプル!

たとえ完全な悪意を無視したとしても、これにはいくつかの実際的な実際的な問題があることを除いて。特に、そのサーバーは失敗するか、インターネットの一部から到達不能になる可能性があります。サーバー障害に対処するには複製が必要であり、それを正しく行うには非常に難しいであり(コンセンサス構築が厄介な理由についてはPaxosアルゴリズムに関する文献を参照)、非常に遅いです。さらに、すべてのサーバーが「ネットの特定の部分から到達できない場合、そのサブネットに接続されているクライアントのnoneは、すべて新しいIDを待機しているため、何でも実行できます。

単純な確率的アルゴリズムを使用して、地球の寿命中に失敗する可能性が低いアルゴリズムを生成するか、(資金)展開PITAであり、頻繁に失敗する主要なインフラストラクチャを構築します。どっちがいいかわかっている。

7
Donal Fellows

代わりのものだけを見ると単純なデータベースアプリケーションの場合、新しいオブジェクトを作成する前に毎回データベースを照会する必要があるため、UUIDを使用するとシステムの複雑さを効果的に減らすことができます。付与-intキーを使用する場合、32ビットであり、128ビットUUIDの4分の1に格納されます。付与-UUID生成アルゴリズムは、単に数値をインクリメントするよりも多くの計算能力を必要とします。しかし-誰が気にしますか? 「権限」を管理して固有の番号を割り当てるオーバーヘッドは、目的の一意性IDスペースに応じて、桁違いに簡単にそれを上回ります。

4
Mirko Klemm

私は衝突の可能性についてのすべての話を取得していません。衝突は気にしません。私はパフォーマンスが気になります。

https://dba.stackexchange.com/a/119129/33649

UUIDは、非常に大きなテーブルのパフォーマンス障害です。 (200K行は「非常に大きい」ではありません。)

CHARCTER SETがutf8の場合、#3は本当に悪いです-CHAR(36)は108バイトを占有します!

UUID(GUID)は非常に「ランダム」です。大きなテーブルでUNIQUEキーまたはPRIMARYキーとして使用することは非常に非効率的です。これは、新しいUUIDを挿入するか、UUIDでSELECTするたびにテーブル/インデックスをジャンプする必要があるためです。テーブル/インデックスが大きすぎてキャッシュに収まらない場合(innodb_buffer_pool_sizeを参照してください。これはRAMより小さく、通常は70%である必要があります)、「次の」UUIDがキャッシュされないため、ディスクヒットが遅くなります。テーブル/インデックスがキャッシュの20倍の大きさである場合、ヒットの1/20(5%)のみがキャッシュされます-I/Oバウンドです。

したがって、次のいずれかの場合を除き、UUIDを使用しないでください。

「小さな」テーブルがあるか、異なる場所から一意のIDを生成するために本当に必要です(そして、別の方法を見つけていません)。 UUIDの詳細: http://mysql.rjweb.org/doc.php/uuid (標準の36文字のUUIDとBINARY(16)の間で変換するための関数が含まれています。)

同じテーブルにUNIQUE AUTO_INCREMENTとUNIQUE UUIDの両方があるのは無駄です。

INSERTが発生した場合、すべての一意のキーまたはプライマリキーの重複をチェックする必要があります。 InnoDBのプライマリキーを持つという要件には、いずれかの一意のキーで十分です。 BINARY(16)(16バイト)は多少かさばります(PKにすることに対する議論)が、それほど悪くはありません。セカンダリキーがある場合、かさ高さが重要になります。 InnoDBは、各セカンダリキーの末尾にPKを静かに追加します。ここでの主な教訓は、特に非常に大きなテーブルの場合、セカンダリキーの数を最小限に抑えることです。比較のために:INT UNSIGNEDは4バイトで、範囲は0〜40億です。 BIGINTは8バイトです。

3
Toskan

ID == lazy design

私はあなたの戦いを選ぶことに同意しません。重複したUUIDが統計的に不可能であり、数学が証明されている場合、なぜ心配ですか?小規模なN UUID生成システムの設計に時間を費やすことは非現実的であり、システムを改善する方法は常に他にもたくさんあります。

3
Johnno Nolan

UUIDはcould(とんでもないくらい小さい確率で)衝突するので設計が悪いと言いますが、DBが生成したキーはそうではありません...予期しないニーズのためにDBが生成したキーは、UUID4の衝突の可能性よりもはるかに高いです。 知っている dbが再作成された場合、idが1から再び開始されます。いつでも未知の未知のものがうまくいかなくなったとき、私はUUIDの安全性にお金をかけました。

1
Iain Duncan

私の最後の仕事では、UUIDで一意に識別されるオブジェクトをサードパーティから取得していました。私はUUID-> long integerルックアップテーブルに入れ、主キーとしてlong integerを使用しました。

1
Paul Tomblin

バージョン1アルゴリズムを使用すると、1ミリ秒あたり10 UUID未満が同じMACアドレスから生成されるという制約の下では、衝突は不可能と思われます

概念的には、UUIDの元の(バージョン1)生成スキームは、UUIDバージョンを、UUIDを生成しているコンピューターのMACアドレスと、西部でのグレゴリオ暦の採用以降の100ナノ秒間隔の数と連結することでした。実際には、実際のアルゴリズムはより複雑です。このスキームは、十分に「不透明」ではないという点で批判されています。 UUIDを生成したコンピューターのIDと、それを実行した時刻の両方が明らかになります。

動作を誤解した場合、誰かが私を修正します

1
Davy8

UUIDを要求する他の誰かのAPIを使用する必要がある場合は別として、もちろん別のソリューションが常にあります。しかし、これらの選択肢はall UUIDが行う問題を解決しますか?一度にすべてのハックを解決できた場合、それぞれ異なる問題を解決するために、ハッキングのレイヤーを追加することになりますか?

はい、理論的にはUUIDが衝突する可能性があります。他の人が指摘しているように、それは単に考慮する価値がないという点にとんでもないほどありそうにない。それは今までに一度も起こらなかったし、おそらくそうなることはないだろう。気にしないで。

衝突を回避するための最も「明白な」方法は、挿入ごとに単一のサーバーに一意のIDを生成させることです。おっとっと。

もう1つの「明白な」ソリューションは、一意の番号のブロックを事前に配布する中央機関です。これは、基本的に、UUID V1が生成マシンのMACアドレスを使用して(IEEE OUIを介して)行うものです。しかし、すべての中央機関が最終的に台無しになるため、重複したMACアドレスが発生するため、実際には、これはUUID V4の衝突よりもはるかに可能性が高くなります。おっとっと。

UUIDを使用することに対する最善の論拠は、それらが「大きすぎる」ということですが、(かなり)小さいスキームでは、最も興味深い問題を解決できないことは避けられません。 UUIDのサイズは、これらの問題を解決する際の有用性の固有の副作用です。

あなたの問題は、UUIDが提供するものを必要とするほど大きくない可能性があり、その場合は、他のものを自由に使用してください。ただし、問題が予想外に大きくなった場合(そしてほとんどの場合)、後で切り替えることになります。成功のために設計するのが同じくらい簡単なのに、なぜ失敗のために設計するのですか?

0
StephenS