web-dev-qa-db-ja.com

Hi / Loアルゴリズムとは何ですか?

Hi/Loアルゴリズムとは何ですか?

これは NHibernate のドキュメント(これは一意のキーを生成する方法の1つであり、セクション5.1.4.2)で見つけましたが、その仕組みについての良い説明は見つかりませんでした。

Nhibernateがそれを処理することは知っています。内部を知る必要はありませんが、私は興味があります。

447
DiegoCofre

基本的な考え方は、主キーを構成するための2つの番号、つまり「高い」番号と「低い」番号があるということです。クライアントは基本的に「高」シーケンスをインクリメントでき、以前の「高」値とさまざまな「低」値の範囲全体からキーを安全に生成できることを知っています。

たとえば、現在の値が35の「高」シーケンスがあり、「低」数の範囲が0〜1023であるとします。次に、クライアントはシーケンスを36にインクリメントし(他のクライアントが35を使用している間にキーを生成できるようにするため)、キー35/0、35/1、35/2、35/3 ... 35/1023がすべて利用可能。

主キーなしで値を挿入してからクライアントに取得する代わりに、クライアント側で主キーを設定できると(特にORMを使用して)非常に便利です。他のこととは別に、親/子関係を簡単に作成し、キーをすべての場所に配置してからanyを挿入できるため、バッチ処理が簡単になります。

509
Jon Skeet

ジョンの答えに加えて:

切断された状態で作業できるようにするために使用されます。クライアントは、サーバーにhi番号を要求し、lo番号自体を増やすオブジェクトを作成できます。 lo範囲が使い果たされるまで、サーバーに接続する必要はありません。

147

Hi/loアルゴリズムは、シーケンスドメインを「hi」グループに分割します。 「hi」値は同期的に割り当てられます。すべての「hi」グループには、最大数の「lo」エントリが与えられます。これは、同時重複エントリを心配することなくオフラインで割り当てることができます。

  1. 「hi」トークンはデータベースによって割り当てられ、2つの同時呼び出しは一意の連続値を確認することが保証されています
  2. 「hi」トークンが取得されると、必要なのは「incrementSize」(「lo」エントリの数)だけです
  3. 識別子の範囲は次の式で与えられます。

    [(hi -1) * incrementSize) + 1, (hi * incrementSize) + 1)
    

    「lo」の値は次の範囲になります。

    [0, incrementSize)
    

    次の開始値から適用されます。

    [(hi -1) * incrementSize) + 1)
    
  4. すべての「lo」値が使用されると、新しい「hi」値がフェッチされ、サイクルが継続します

より詳細な説明は この記事 にあります:

また、この視覚的なプレゼンテーションも簡単に理解できます。

enter image description here

Hi/loオプティマイザーは識別子生成の最適化には適していますが、識別子戦略について何も知らない限り、データベースに行を挿入する他のシステムとはうまく機能しません。

Hibernateは pooled-lo オプティマイザーを提供します。これは、hi/loジェネレーター戦略と相互運用性シーケンス割り当てメカニズムを組み合わせたものです。このオプティマイザーは、効率的であり、他のシステムと相互運用可能であり、以前のレガシーhi/lo識別子戦略よりも優れた候補です。

24
Vlad Mihalcea

Loは、人間が賢明に選択する意味のあるサイズの範囲(たとえば、一度に200のキーを取得する)ではなく、通常はマシンのWordサイズに基づいて、キースペースを大きなチャンクに分割するキャッシュアロケーターです。

Hi-Loを使用すると、サーバーの再起動時に大量のキーが無駄になり、人間にとって使いにくい大きなキー値が生成される傾向があります。

Hi-Loアロケーターよりも優れているのは、「Linear Chunk」アロケーターです。これは、同様のテーブルベースの原則を使用しますが、小さくて便利なサイズのチャンクを割り当て、人間に優しい値を生成します。

create table KEY_ALLOC (
    SEQ varchar(32) not null,
    NEXT bigint not null,
    primary key (SEQ)
);

次の、たとえば200個のキーを割り当てるには(キーはサーバー内の範囲として保持され、必要に応じて使用されます):

select NEXT from KEY_ALLOC where SEQ=?;
update KEY_ALLOC set NEXT=(old value+200) where SEQ=? and NEXT=(old value);

このトランザクションをコミットできる(競合を処理するために再試行を使用する)ことを提供し、200個のキーを割り当て、必要に応じてそれらを分配できます。

チャンクサイズがわずか20であるため、このスキームはOracleシーケンスから割り当てるよりも10倍速く、すべてのデータベース間で100%移植可能です。割り当てパフォーマンスはhi-loと同等です。

Amblerのアイデアとは異なり、キースペースを連続した線形のナンバーラインとして扱います。

これにより、複合キーの推進力(これは決して良いアイデアではありませんでした)が回避され、サーバーの再起動時にローワード全体が無駄になりません。 「フレンドリー」な人間スケールのキー値を生成します。

それに対して、アンブラー氏のアイデアは、上位16ビットまたは32ビットを割り当て、ハイワードが増加するにつれて、人間にとって使いにくい大きなキー値を生成します。

割り当てられたキーの比較:

Linear_Chunk       Hi_Lo
100                65536
101                65537
102                65538
.. server restart
120                131072
121                131073
122                131073
.. server restart
140                196608

デザイン面では、彼のソリューションは、Linear_Chunkよりも基本的に番号行(複合キー、大きなhi_Word製品)で複雑ですが、比較の利点はありません。

Hi-Loデザインは、OOマッピングおよび永続化の初期に生まれました。最近のHibernateなどの永続化フレームワークは、デフォルトとしてよりシンプルで優れたアロケーターを提供します。

20
Thomas W

Hi/Loアルゴリズムは、私の経験に基づいたレプリケーションシナリオを持つ複数のデータベースに最適です。これを想像してください。ニューヨーク(別名01)にサーバーがあり、ロサンゼルス(別名02)に別のサーバーがある場合、PERSONテーブルがあります...ニューヨークでは、人が作成されるとき... HI値として常に01を使用します。また、LO値は次のセクショナルです。 porの例。

  • 010000010ジェイソン
  • 010000011デビッド
  • 010000012テオ

ロサンゼルスでは、常にHI 02を使用します。例:

  • 020000045ルパート
  • 020000046オズワルド
  • 020000047マリオ

したがって、データベースレプリケーションを使用すると(ブランドに関係なく)、すべてのプライマリキーとデータは、プライマリキーの重複や衝突などを心配することなく簡単かつ自然に結合されます。

これは、このシナリオに進むのに最適な方法です。

1
Theo