6

いくつかの情報を維持し、順序を維持するために必要なデータベース テーブルがあります。基本的に、要素 1 ~ 5 がリストされていて、新しい要素を追加したい場合、既存の行の最後、5 の後、1 の前の始まり、または 3 の後などの途中のどこかに挿入できます。 . MySQL INSERT ステートメントを使用して、どの行の後にインデックスを挿入するかを指定する方法はありますか?

私はそうではないと思います。したがって、これを行うための私の戦略は、基本的に要素の順序を記録する別の列「order_number」を作成することです。たとえば、レコード テーブルにプライマリ キー (record_id) と order_number が並んでいる場合、次のようになります。

 record_id     order_number

    1              1    
    2              2    
    3              3
    4              4
    5              5

行 3 の後にこの行に新しい要素を追加すると、最終テーブルは次のようになります。

 record_id     order_number

    1             1
    2             2
    3             3
  **6**         **4**         <------ added row 
    4           **5**         <-- changed order_number
    5           **6**         <-- changed order_number

このような状況では、必要なデータを選択し、Order By order_number asc 句を指定するだけで、目的の順序を明確に達成できます。

ただし、ご覧のとおり、単純な挿入を行うには、その後に表示される 1 行おきに order_number を更新する必要があります。テーブルには、少なくとも大量の行 (大きさ 100,000) があることが予想され、1 回の挿入操作で 1 行おきに単純に更新する (したがって、テーブルをロックする) ことは、まったく現実的ではありません。

この場合、より推奨される戦略は何ですか?

4

2 に答える 2

17

を表示せorder_numberず、順序付けのみに使用する場合は、integer の代わりに decimal データ型を使用することをお勧めします。このように、2 つの既存の行の「間に」行を挿入する必要がある場合、既存の 2 つの注文番号の平均を order_number として設定できます。

あなたの例では:

 record_id     order_number

    1             1.0
    2             2.0
    3             3.0
  **6**           3.5          <---- added row 
    4             4.0           <-- no change
    5             5.0           <-- no change

ただし、同じ領域に数字を挿入し続けると、選択したデータ型の精度に対して順序番号が近すぎて、互いに区別できないほど近くなるという問題があります。

これを回避するには、挿入手順で、2 つの既存の注文番号が近すぎるかどうかを調べる必要があります。その場合、他の近くの行のいくつかの順序番号を再割り当てし、上下の順序番号を「引き延ばして」、新しい値のための「スペースを作る」ことができます。

また、定期的に実行され、テーブル全体または大部分でこの「ストレッチ」を行う「クリーンアップ」手順を使用することもできます。

于 2012-12-02T23:52:46.550 に答える
5

同様の質問に対するこの回答を見つけました: https://stackoverflow.com/a/6333717/1010050

要約すると、一貫性を維持するために、追加するものよりも下のすべてのレコード ID をインクリメントします。それでもすべてのレコード ID を更新する必要があるため、最も効率的ではありません。あなたの方法と比較して、あなたのような仮想的な順序ではなく、データベース内の物理的な順序を維持するという利点があります。

私が考えることができる別の方法は、双方向リンクリストと同様に、注文番号ではなく、各レコードの子レコード ID と親レコード ID を記録することです。要素を途中に挿入すると、テーブルのサイズに関係なく、他の 2 つのレコードを更新するだけで済みます。これには、物理​​的な順序が間違っているソリューションと同じ欠点があるため、順序付けられた方法でテーブルから読み取ると、よりコストがかかります。

例えば:

record_id        parent_id      child_id
   0                 NULL          1
   1                 0             2
   2                 1             NULL

の後にレコードを挿入するrecord_id = 1と、テーブルは次のようになります。

record_id        parent_id      child_id
   0                 NULL          1
   1                 0             3
   2                 3             NULL
   3                 1             2

ID 1 と 2のparent_idとのみを変更する必要があることに注意してください。child_id

これら 2 つの解決策の間で考慮すべき最大のことは、最も一般的な操作は何かということです。値を順番に読み取るか、途中で新しい値を書き込むかです。読み取り中の場合は、データベースの物理的な順序を維持するために、レコード ID を更新することが最善の方法です。書く場合は、私が提案した双方向リンクリストに似た方法、または独自の順序方法を使用して、それを最適化できます。

質問の更新後の要約: ほとんどのレコードを更新することは不可能であることを確認すると、私が見つけた他の回答は間違いなく有効ではありません。ただし、二重にリンクされたリストと同様に扱うという解決策は、まだもっともらしいです。

于 2012-12-02T23:57:17.327 に答える