HiLoジェネレーターを使用してテーブルにIDを割り当て始めてから、容量(つまり最大の「lo」値)を増減することにした場合、これにより、すでに割り当てられているIDとの衝突が発生しますか?
「これは絶対に変えないで!」という数字の周りに大きな赤い旗を立てる必要があるのではないかと思っています。
注-NHibernate固有ではなく、HiLoアルゴリズム全般について知りたいだけです。
一般に、HiLoアルゴリズムは、2つの整数を1つの整数IDにマップします。これにより、番号のペアがデータベースごとに一意になることが保証されます。通常、次のステップは、一意の数値のペアが一意の整数IDにマップされることを保証することです。
HiLoが概念的にどのように機能するかについての良い説明は、この以前のSOの回答に記載されています。
max_loを変更すると、数値のペアが一意になるというプロパティが保持されます。ただし、マップされたIDが一意であり、衝突がないことを確認しますか?
HibernateによるHiLoの実装を見てみましょう。彼らが使用しているように見えるアルゴリズム(私が集めたものから)は次のとおりです:(そして私は専門性に欠けているかもしれません)
h = high sequence (starting at 0)
l_size = size of low block
l = low sequence (starting at 1)
ID = h*l_size + l
したがって、下位ブロックがたとえば100の場合、予約済みIDブロックは1-100、101-200、201-300、301-400になります...
Highシーケンスは3になりました。突然l_sizeを10に変更した場合はどうなりますか?次のブロック、Highがインクリメントされ、次のようになります4*10+1 = 41
おっと。この新しい値は、間違いなくの「予約済みブロック」に含まれ1-100
ます。シーケンスが0の高い人は、「まあ、私は1-100
自分のためだけに範囲を予約しているので41
、安全だとわかっているので、1つだけに置きます」と思うでしょう。
l_maxを下げると、衝突の可能性が非常に高くなります。
反対の場合、それを上げるのはどうですか?
例に戻って、l_sizeを500に上げ、次のキーをに変えて4*500+1 = 2001
、範囲2001-2501を予約しましょう。
この特定のHiLoの実装では、l_maxを上げると、衝突が回避されるようです。
もちろん、これが実際の実装であるか、それに近いことを確認するために、独自のテストを行う必要があります。1つの方法は、l_maxを100に設定して最初のいくつかのキーを見つけ、次にそれを500に設定して次のキーを見つけることです。ここで述べたような大きなジャンプがあれば、あなたは安全かもしれません。
ただし、既存のデータベースでl_maxを上げることがベストプラクティスであることを示唆しているわけではありません。
あなた自身の裁量を使用してください。HiLoアルゴリズムは、l_maxを変化させることを念頭に置いて作成されたものではなく、正確な実装によっては、最終的に結果が予測できない場合があります。たぶん、l_maxを上げて問題を見つけた経験のある人なら、このカウントが正しいことを証明できます。
したがって、結論として、理論的には、HibernateのHiLo実装は、l_maxが発生したときに衝突を回避する可能性が最も高いとはいえ、それでもおそらく良い習慣ではありません。l_maxが時間の経過とともに変化しないかのようにコーディングする必要があります。
しかし、あなたが幸運を感じているなら...
Linear Chunk テーブル アロケータを参照してください。これは、論理的には、同じ問題に対するより単純で正しいアプローチです。
数値空間から範囲を割り当ててNEXT
直接表現することで、上位の単語や乗算された数値でロジックを複雑にするのではなく、どのキーが生成されるかを直接確認できます。
基本的に、「リニア チャンク アロケータ」は乗算ではなく加算を使用します。NEXT が 1000 で、range-size を 20 に設定した場合、NEXT は 1020 に進み、割り当てのためにキー 1000 ~ 1019 を保持します。
レンジサイズは、整合性を失うことなく、いつでも調整または再構成できます。アロケータの NEXT フィールド、生成されたキー & テーブルに存在する MAX(ID) の間には直接的な関係があります。
(比較すると、「Hi-Lo」は乗算を使用します。次が 50 で乗数が 20 の場合、1000 ~ 1019 前後のキーを割り当てています。NEXT、生成されたキー、および MAX(ID) の間に直接的な相関関係はありません。 NEXT を安全に調整することは難しく、現在の割り当てポイントを乱すことなく乗数を変更することはできません。)
「リニア チャンク」を使用すると、各範囲/チャンクの大きさを構成できます。サイズ 1 は、従来のテーブル ベースの「単一アロケータ」と同等であり、データベースにヒットして各キーを生成します。サイズ 10 は、割り当て時に 10 倍速くなります。一度に10の範囲、50または100のサイズはさらに高速です..
65536 のサイズは見栄えの悪いキーを生成し、サーバーの再起動時に膨大な数のキーを浪費し、Scott Ambler のオリジナルの HI-LO アルゴリズムと同等です。
要するに、Hi-Lo は、数直線に沿って範囲を割り当てるという、概念的に自明な単純であるべきものに対する、誤って複雑で欠陥のあるアプローチです。
単純な helloWrold 風の休止状態アプリケーションを使用して、HiLo アルゴリズムの動作を明らかにしようとしました。
私は休止状態の例を試しました
<generator class="hilo">
<param name="table">HILO_TABLE</param>
<param name="column">TEST_HILO</param>
<param name="max_lo">40</param>
</generator>
単一の列「TEST_HILO」で作成された「HILO_TABLE」という名前のテーブル最初に、TEST_HILO列の値を8に設定しました。
update HILO_TABLE set TEST_HILO=8;
IDを作成するパターンは
hivalue * lowvalue + hivalue
hivalue は DB の列の値です (つまり、 HILO_TABLE から TEST_HILO を選択します) lowvalue は config xml (40) からのものです
したがって、この場合、ID は 8*40 + 8 = 328 から始まります
私の休止状態の例では、1 つのセッションで 200 行を追加しました。そのため、行は ID 328 から 527 で作成され、DB では hivalue が 13 までインクリメントされました。インクリメント ロジックは次のようです:-
new hivalue in DB = inital value in DB + (rows_inserted/lowvalue + 1 )
= 8 + 200/40 = 8 + 5 =13
行を挿入するために同じ休止状態プログラムを実行すると、ID は 13*40 + 13 = 533 から始まるはずです。
プログラムを実行すると、それが確認されました。
経験上、私はこう言います:はい、減少すると衝突が発生します。max lowが低い場合、データベースの高い値に関係なく、低い数値が得られます(これは同じ方法で処理されます。たとえば、NHの場合は各セッションファクトリインスタンスで増分します)。
増加しても衝突が発生しない可能性があります。しかし、あなたは私が確信するよりもよく知っている誰かに試してみるか、尋ねる必要があります。