設計の一部として本当にUUIDを使用する必要があるのはいつですか?


123

UUIDの要点は本当にわかりません。私は衝突の確率が事実上nilであることを知っていますが、事実上nilは不可能に近いものではありません。

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

UUIDは、グローバル変数のような匂いがします。グローバル変数がより単純な設計を実現する方法はたくさんありますが、それは単に怠惰な設計です。


23
すべてが失敗する可能性はゼロではありません。UUIDの衝突よりもはるかに発生しやすい問題(つまり、考えられるほとんどすべてのもの)に集中します
DanSingerman 2009年

16
実際、「事実上ゼロ」は不可能に非常に近い。
mqp 2009年

21
いいえ、実際には不可能から遠くはありません
Pyrolistical 2009年

32
@Pyrolistical "infinity"のような単語を使い始めると、ソフトウェア開発の世界から離れました。コンピュータサイエンス理論は、実際のソフトウェアを書くこととはまったく異なる議論です。
Rex M

2
gitのsha1がハッシュの良さを私に納得させたので、主にクローズします
Pyrolistical

回答:


617

私は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ずつ増加します。次のいずれかが発生しない限り、衝突は発生しません。MACアドレスがスプーフィングされている。2つの異なるUUID生成アプリケーションを実行している1台のマシンが、まったく同時にUUIDを生成します。ネットワークカードがない、またはMACアドレスへのユーザーレベルのアクセスがない2台のマシンには、同じランダムノードシーケンスが与えられ、まったく同じ時にUUIDを生成します。

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

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


8
これは断然最良の説明です。なぜこれがトップに投票されていないのか分かりません。Sporkmongerへの称賛。
ブラッド・バーカー、

1
@Chamnap私はUUIDToolsを書きました。UUIDは整数または未加工のバイト形式に変換でき、バイナリとしてはかなり小さくなります。
Bob Aman

1
@Chamnap uuid.rawはバイト文字列を提供します。このhash方法は役に立ちません。Rubyの内部でハッシュテーブルと比較演算に使用されます。さまざまなUUID表現との間で変換するためのすべてのメソッドは、クラスメソッドとして定義されており、接頭辞としてを付ける必要があり"parse"ます。
Bob Aman

3
@BobAman 1990年にAegisシステムでUUIDの衝突が12回発生しましたが、FPUに問題があることが判明しましたが、発生する可能性があることをお知らせします(ただし、過去30年以上のプログラミング以外では発生していません)。 。いい説明ですが、これは今、人々に提供するための私の事実上のUUID参照の投稿です:)
GMasucci 14

2
@kqr誕生日の問題であることは間違いなく正しいですが、nビットコードの場合、誕生日のパラドックスの問題は2 ^(n / 2)に減少します。 。
Bob Aman

69

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"という名前の誰か(または何か)がいても混乱しないように。


1
具体例?COM / DCE UUID-それらを割り当てるための権限はありません。だれも責任を負うことを望んでおらず、権限を付与することを望んでいません。信頼できるリンクとマスターがない分散データベース。
Michael Burr

3
より具体的な例-銀行アプリケーション。各国に1つずつ、複数のデータセンターが設置されており、各データセンターにはDBがあります。複数の設備があり、異なる規制に準拠しています。のみすべての顧客のためのセット全体で1つの顧客レコードを.....がある場合もあります
Vineetレイノルズ

(前のコメントの続き)全体的なレポートと追跡の目的で(すべてのインストール全体で)顧客IDを生成する中央サーバーが必要か、個々のインストールで顧客IDとして機能するUUIDを生成する必要があります(明らかに、UUIDはレポート)。
Vineet Reynolds

重複の可能性が50%になるまでに、すでに溺死しています。誰かが0.0000001%の確率を得るのに必要な量を指摘しています。1からnで始まり、毎回nずつ増加する複数の自動インクリメントデータベースは、同じ問題を効果的に解決します。
ゴードン

2
複製を取得する確率はFARであり、中央当局がミッションクリティカルな方法で失敗する確率よりも低い
std''OrgnlDave

33

すべてが失敗する可能性はゼロではありません。UUIDの衝突よりもはるかに発生しやすい問題(つまり、考えられるほとんどすべてのもの)に集中します


Pyrolisticalのリクエストに回答として追加
DanSingerman

16

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

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


解決。怠惰にして参照を更新しないでください。ちゃんとして。
Pyrolistical 2009年

8
これは遅延とは関係がありません-アイテムのIDが永続的で不変であると見なされるというポリシーの場合、IDは変更されません。したがって、IDを最初から一意にして、すべてのシステムを最初から何らかの方法で接続する必要がないようにする必要があります。
Michael Burr

コンテキストが必要です。競合する可能性のある一意のIDのグループが2つある場合は、それらを分離するための高レベルのコンテキストが必要です
Pyrolistical 2009年

23
または、UUIDを使用するシステムを構築してそれを出荷し、販売し、100万ドルを稼ぎ、2つのIDが衝突しないという単一のクレームが発生しないため、まったく聞こえないこともあります。
Rex M

16

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

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

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

とにかく、衝突の可能性についてのウィキペディアからの言葉:

これらの数値を考慮すると、隕石に当たる年間リスクは170億回に1回と推定されます。これは、年間に数十兆のUUIDを作成し、複製を1つ作成する確率に相当します。つまり、今後100年間、毎秒10億個のUUIDを生成した後にのみ、複製が1つだけ作成される確率は約50%になります。


4
簡単です。オフラインのユーザーにキーを生成させないでください。システムがオンラインになるまで一時キーを割り当てて、実際のキーを生成できるようにします。
Pyrolistical 2009年

これは私の意見では非常に役立つ回答です... OPが意味を完全に理解していないように見えたので、私自身の確率にある種の類推を提供するつもりでしたが、あなたはそれをしたようです。
Noldorin 2009年

確率が事実上ゼロであることを静かに理解しています。私にとってUUIDの使用は遅延設計であり、常にそれを回避できるかどうかを確認したかっただけです
Pyrolistical 2009年

極端な状況でも低い確率を考慮する必要があることがわかっている限り、これで十分です。
Noldorin 2009年

13

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

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

UUIDでは一致しないため、これは発生しません。(ほぼ間違いなく)


1
では、DB Aが偶数IDを使用し、DB Bが奇数IDを使用するようにします。完了しました。UUIDはありません。
Pyrolistical 2009年

2
3つのDBがある場合は、3の倍数のLOLを使用します
Jhonny D. Cano -Leftware- 2009年

20
2/3 /倍数を使用する場合、後で新しいサーバーをミックスに追加するとどうなりますか?新しいサーバーでn + 1の倍数を使用するようにスイッチを調整し、古いサーバーをすべて新しいアルゴリズムに移動する必要があります。これを実行している間は、衝突を避けるためにすべてをシャットダウンする必要があります。アルゴリズムの切り替え。または... EVERYONE ELSEのようなUUIDを使用することもできます。
ボブ・アマン

3
それよりもさらに悪いのは、2の倍数と4の倍数をどのように区別するかです。または、3の倍数対6の倍数ですか?実際、素数の倍数に固執する必要があります。ブレッチ!UUIDを使用するだけで機能します。マイクロソフト、アップル、そして数えきれないほどの人々がそれらに依存し、それらを信頼しています。
sidewinderguy 2013年

2
@sidewinderguy、信頼できるGUIDで!:)
ロンクライン

13

また、身体のすべての粒子が同時に、座っている椅子を通り抜け、突然床に座っていることに気付く可能性もあります。

気になりますか?


7
もちろん、それは私が制御できるものではありませんが、私が制御できるデザインです。
Pyrolistical 2009

4
@Pyrolisticalされていることを本当に、私は本当にあなたがそのことについて心配しない理由を意味ですか?その後、あなたはかなり奇妙です。さらに、あなたは正しくありません。あなたそれ制御することができます。あなたが数ポンドを得るならば、あなたはそのような出来事の可能性をかなり減らします。それなら体重を増やすべきだと思いますか?:-)
2015

8

UUIDを回避するためのスキームがあります。サーバーをどこかにセットアップし、それを用意して、ソフトウェアの一部が普遍的に一意の識別子を必要とするたびに、そのサーバーに連絡して1つ渡すようにします。シンプル!

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

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


2
実際、UUIDの発明の要点は、あなたのアプローチを回避することでした。UUIDの履歴を調査すると、洗練された意味のあるコンピューターネットワークを作成する最初の実験から派生したことがわかります。彼らは、ネットワークが本質的に信頼できず、複雑であることを知っていました。UUIDは、コンピュータが常に通信できないことがわかっているときに、コンピュータ間でデータを調整する方法の質問への回答でした。
バジルブルク

7
@BasilBourqueそれが明白でない場合に備えて、私はその最初の段落で皮肉を使用していました。
ドナルフェロー

5

私は衝突の可能性についてすべての話をするわけではありません。衝突は気にしません。でもパフォーマンスは気にしています。

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

UUIDは、非常に大きなテーブルのパフォーマンスが低下します。(20万行は「非常に大きい」わけではありません。)

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〜44億です。BIGINTは8バイトです。


4

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


3

UUID == lazyデザインについて

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


1

私の最後の仕事では、UUIDで一意に識別されるオブジェクトをサードパーティから取得していました。UUID-> long integer lookup tableに入れ、long integerを主キーとして使用したのは、その方法の方が高速だったからです。


確かに、サードパーティがUUIDの使用を強制することは、私が知りたくないもう1つの問題です。UUIDを使用するかどうかを制御できると仮定します。
Pyrolistical 2009年

まあ、「長整数」(128ビット)は実際にはUUIDです。人間が消費するための文字列として示されているだけです。時々それはそのように送信されるかもしれません、しかし、あなたが見つけたように、それはストレージとインデックスのためにそれが整数形式で確かにより速くなります。
ニコール

1

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

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

それがどのように機能するかを誤って解釈した場合、誰かが私を修正します


多くのバージョンがあり、Macアドレスにアクセスする純粋なJava方法がないため、多くのソフトウェアシステム(Javaなど)はバージョン1を使用できません。
Pyrolistical 2009年

JavaがMACアドレスを取得できないことについて:完全に正しいわけではありません。これには回避策があります。ジェネレーターが使用するMACアドレスは、設定ファイルを使用して手動で設定できます。ifconfigを呼び出して、出力を解析することもできます。私が書いたRuby UUIDジェネレーターは、両方のアプローチを使用しています。
Bob Aman、

また、私の回答で述べたように、バージョン1のUUIDのMACアドレスを取得できない場合は、RFC 4122のセクション4.5に従って、代わりにランダムな6バイトを使用します。したがって、 Javaの2つの回避策でも、有効なバージョン1 UUIDを生成できます。
Bob Aman、

MS GUIDは単なる乱数です。サーバーのMACアドレスをリバースエンジニアリングすることが可能になったため、MACの部分はもうありません(非常に危険であることが判明しました)。
Stefan Steiger

1

UUIDは(途方もなく小さな確率で)衝突する可能性があるために設計が悪いと言っているが、DB生成キーはそうではない...いくつかのun -予見される必要性は、UUID4衝突の可能性よりも高いFAR FAR FARです。私たちは知っている DBが再作成されている場合、それは再び1でIDSを開始することを、どのように私たちの多くは、私たちは必ず私たちが今までに必要ないだろうだったとき、テーブルを再作成しなければなりませんでしたか?いつの日か、unknown-unknownsで問題が発生し始めたら、私はUUIDの安全性にお金をかけます。


0

UUIDを要求する他の誰かのAPIを使用しなければならない場合を除いて、もちろん別の解決策があります。しかし、それらの代替案はUUIDが行うすべての問題を解決するでしょうか?一度にすべてのハックを解決できたとしても、それぞれが別の問題を解決するために、ハックの層をさらに追加することになりますか?

はい、理論的にはUUIDが衝突する可能性があります。他の人が指摘しているように、検討するだけの価値がないということは、途方もなく可能性が低いです。これまでに起こったことはなく、おそらくそうなることもないでしょう。気にしないで。

衝突を回避する最も「明白な」方法は、単一のサーバーがすべての挿入で一意のIDを生成できるようにすることです。これは明らかに深刻なパフォーマンスの問題を引き起こし、オフライン生成の問題をまったく解決しません。おっとっと。

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

UUIDの使用に対する最良の議論は、それらが「大きすぎる」ということですが、(大幅に)小さいスキームは、最も興味深い問題の解決に必然的に失敗します。UUIDのサイズは、それらの問題そのものを解決する上でのそれらの有用性の固有の副作用です。

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


-10

UUIDは、グローバル変数に関連するすべての悪いコーディング慣行を具現化しますが、さらに悪いのは、それらがキットのさまざまな部分に分散できるスーパーグローバル変数であるためです。

最近、プリンターを正確な交換モデルに交換することでこのような問題が発生し、クライアントソフトウェアが機能しないことがわかりました。


2
私たちがランダムな意見ではなく事実に焦点を合わせている社会に住んでいることをうれしく思います。さもなければ、スタックオーバーフローの私たち全員が仕事を失うことになります。:)
マカランド2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.