96

MySQLデータベースの主キーとしてUUID値を使用することを検討しています。挿入されるデータは、数十、数百、さらには数千のリモートコンピューターから生成され、1秒あたり100〜40,000の挿入速度で挿入され、更新は行われません。

データベース自体は通常、データのカリングを開始する前に約5,000万レコードに達するため、大規模なデータベースではありませんが、小規模でもありません。また、InnoDBで実行することも計画していますが、実行していることに対してより優れたエンジンがあれば、それを変更することもできます。

Javaのタイプ4UUIDを使用する準備ができましたが、テストでは奇妙な動作が見られました。1つは、varchar(36)として格納しているため、binary(16)を使用した方がよいことに気付きましたが、どれだけ良いかはわかりません。

より大きな問題は、5,000万件のレコードがある場合、このランダムデータがインデックスをどれほどひどく台無しにするかということです。たとえば、左端のビットにタイムスタンプが付けられたタイプ1 UUIDを使用した方がよいでしょうか?または、UUIDを完全に破棄して、auto_increment主キーを検討する必要がありますか?

MySQLにインデックス/主キーとして格納されている場合のさまざまなタイプのUUIDのパフォーマンスに関する一般的な考え/ヒントを探しています。ありがとう!

4

10 に答える 10

86

私の仕事では、PKとしてUUIDを使用しています。私が経験から言えることは、それらをPKとして使用しないでください(ちなみにSQL Server)。

これは、レコード数が1000未満の場合は問題ありませんが、数百万の場合は最悪の事態です。なんで?UUIDはシーケンシャルではないため、新しいレコードが挿入されるたびに、MSSQLはレコードを挿入する正しいページを確認してから、レコードを挿入する必要があります。これによる本当に醜い結果は、ページがすべて異なるサイズになり、断片化されてしまうことです。そのため、定期的に断片化解除を行う必要があります。

自動インクリメントを使用すると、MSSQLは常に最後のページに移動し、(理論的には)同じサイズのページになるため、これらのレコードを選択するパフォーマンスが大幅に向上します(また、INSERTがテーブル/ページをブロックしないため)さよなら)。

ただし、UUIDをPKとして使用することの大きな利点は、DBのクラスターがある場合、マージ時に競合が発生しないことです。

次のモデルをお勧めします。1。PKINTIdentity2.UUIDとして自動的に生成される追加の列。

このようにして、マージプロセスが可能になります(UUIDはREALキーになりますが、PKはパフォーマンスを向上させる一時的なものになります)。

注:最善の解決策はNEWSEQUENTIALIDを使用することです(コメントで言ったように)が、リファクタリングする時間があまりない(さらに悪いことに、すべての挿入を制御しない)レガシーアプリの場合、それを行うことはできません。しかし実際、2017年の時点で、ここでの最善の解決策はNEWSEQUENTIALIDか、NHibernateでGuid.Combを実行することだと思います。

お役に立てれば

于 2011-09-28T04:56:14.477 に答える
38

UUIDは、UniversallyUniqueIDです。ここで検討する必要があるのは、普遍的な部分です。

IDが普遍的に一意である必要が本当にありますか?その場合、UUIDが唯一の選択肢になる可能性があります。

UUIDを使用する場合は、文字列ではなく数値として格納することを強くお勧めします。5,000万以上のレコードがある場合、ストレージスペースを節約すると、パフォーマンスが向上します(ただし、どれだけかはわかりません)。

IDが普遍的に一意である必要がない場合は、auto_incrementを使用するよりもはるかに優れているとは思いません。これにより、IDがテーブル内で一意になることが保証されます(値は毎回インクリメントされるため)

于 2010-03-02T17:20:11.280 に答える
27

考慮すべき点は、自動インクリメントは一度に1つずつ生成され、並列ソリューションを使用して解決することはできないということです。UUIDを使用するための戦いは、最終的には、達成したいことと、潜在的に犠牲にすることのどちらになりますか。

パフォーマンスについて、簡単に

上記のようなUUIDは、ダッシュを含めて36文字の長さです。このVARCHAR(36)を保存すると、比較パフォーマンスが大幅に低下します。これが主キーです。遅くしたくないです。

そのビットレベルでは、UUIDは128ビットです。これは、16バイトに収まることを意味します。これは人間があまり読めないことに注意してください。ただし、ストレージを低く保ち、32ビット整数の4倍、つまり2です。 64ビット整数の倍の大きさ。VARBINARY(16)を使用します。理論的には、これは多くのオーバーヘッドなしで機能します。

次の2つの投稿を読むことをお勧めします。

私は2つの間で考えます、彼らはあなたの質問に答えます。

于 2010-03-02T17:24:46.467 に答える
4

保存するのが面倒で、主キーとして使用するのが面倒であるという理由だけでUUIDを避ける傾向がありますが、利点があります。主なものは彼らがユニークであるということです。

私は通常、問題を解決し、デュアルキーフィールドを使用してUUIDを回避します。

COLLECTOR=マシンに割り当てられた一意

ID = COLLECTORによって収集されたレコード(auto_incフィールド)

これは私に2つのことを提供します。自動インクフィールドの速度と、データが収集されてグループ化された後、中央の場所に保存されるデータの一意性。また、データが収集された場所を閲覧しているときに、それが私のニーズにとって非常に重要であることがよくあります。

UUIDを使用することを決定したクライアントの他のデータセットを処理しているときに多くのケースを目にしましたが、それでもデータが収集されたフィールドがあり、これは本当に労力の無駄です。キーとして2つ(または必要に応じてそれ以上)のフィールドを使用するだけで、本当に役立ちます。

UUIDを使用したパフォーマンスヒットが多すぎます。彼らはチートのように感じます...

于 2012-10-16T17:32:38.253 に答える
3

挿入ごとに一意のキーを一元的に生成するのではなく、キーのブロックを個々のサーバーに割り当てるのはどうでしょうか。キーがなくなると、新しいブロックを要求できます。次に、インサートごとに接続することにより、オーバーヘッドの問題を解決します。

キーサーバーは次に利用可能なIDを維持します

  • サーバー1はIDブロックを要求します。
  • キーサーバーは(1,1000)を返します
    サーバー1は、新しいブロックを要求する必要があるまで1000レコードを挿入できます
  • サーバー2はインデックスブロックを要求します。
  • キーサーバーは(1001,2000)を返します
  • 等...

サーバーが必要なキーの数を要求したり、未使用のブロックをキーサーバーに返したりできる、より洗練されたバージョンを考え出すことができます。これにより、もちろん、使用済み/未使用のブロックのマップを維持する必要があります。

于 2014-12-13T15:56:28.207 に答える
3

私はこの質問がかなり古いことに気づきましたが、私は自分の研究でそれを思いつきました。多くのことが起こったので(SSDは至る所にありますInnoDBは更新などを取得しました)。

私の調査では、パフォーマンスに関するこのかなり興味深い投稿を見つけました。

GUID / UUIDインデックスツリーのランダム性のために、ツリーがかなり不均衡になる可能性があると主張します。MariaDB KBで、解決策を提案する別の投稿を見つけました。しかし、新しいUUID_TO_BINがこれを処理するので。この関数は、MySQL(テスト済みバージョン8.0.18)でのみ使用でき、MariaDB(バージョン10.4.10)では使用できません。

TL; DR:変換/最適化されたBINARY(16)値としてUUIDを格納します。

于 2020-12-28T08:38:04.633 に答える
2

トランザクション方式で各サーバーに数値IDを割り当てます。次に、挿入された各レコードは、それ自体のカウンターを自動インクリメントします。ServerIDとRecordIDの組み合わせは一意になります。ServerIDフィールドにインデックスを付けることができ、ServerIDに基づく将来の選択パフォーマンス(必要な場合)がはるかに優れている可能性があります。

于 2011-02-15T01:49:00.930 に答える
2

簡単に言うと、多くのデータベースでは、インデックス作成方法とUUIDの上位ビットの意図的なエントロピーとの競合が原因で、パフォーマンスの問題が発生します(特にINSERTボリュームが多い場合)。一般的なハックがいくつかあります。

  • それを気にしない別のインデックスタイプ(たとえば、MSSQLで非クラスター化)を選択します
  • データを変更して、エントロピーを下位ビットに移動します(たとえば、MySQLでのV1 UUIDのバイトの並べ替え)
  • 自動インクリメントint主キーを使用してUUIDを副キーにします

...しかし、これらはすべてハックであり、おそらくそれは壊れやすいものです。

最善の答えですが、残念ながら最も遅いのは、ベンダーに製品の改善を要求して、他のタイプと同じようにUUIDを主キーとして処理できるようにすることです。彼らは、一般的なユースケースになり、成長し続けるだけの問題を解決できなかったことを補うために、自分で中途半端なハックを実行するように強制するべきではありません。

于 2018-07-31T21:47:47.717 に答える
1

手作りのUIDはどうですか?何千ものサーバーのそれぞれにIDを与え、主キーを自動インクリメントのコンボキー、MachineIDにしますか?

于 2010-03-02T18:08:56.473 に答える
1

主キーは分散して生成されるため、とにかくauto_incrementを使用するオプションはありません。

リモートマシンのIDを非表示にする必要がない場合は、UUIDの代わりにタイプ1UUIDを使用してください。それらは生成が簡単で、少なくともデータベースのパフォーマンスを損なうことはありません。

同じことがvarchar(char、実際)とbinaryにも当てはまります。それは問題を解決するだけです。パフォーマンスがどれだけ向上するかは本当に重要ですか?

于 2010-03-03T00:23:16.760 に答える