13

オラクルを使用しています

IDusingmax(id)+1と usingを作成するときsequance.nexval、どこでいつ使用するかの違いは何ですか?

お気に入り:

insert into student (id,name) values (select max(id)+1 from student, 'abc');

insert into student (id,name) values (SQ_STUDENT.nextval, 'abc');

SQ_STUDENT.nextvalレコードが重複しているというエラーが表示されることがあります...

この疑問について私を助けてください

4

4 に答える 4

35

このselect max(id) + 1アプローチでは、同時に挿入する 2 つのセッションがテーブルから同じ現在の最大 ID を参照し、両方が同じ新しい ID 値を挿入します。これを安全に使用する唯一の方法は、トランザクションを開始する前にテーブルをロックすることです。これは面倒であり、トランザクションをシリアル化します。(Stijn が指摘しているように、最上位のレコードが削除された場合、値を再利用できます)。基本的に、このアプローチは使用しないでください。(やむを得ない理由がある場合が非常にまれにあるかもしれませんが、実際に見たことがあるかどうかはわかりません)。

シーケンスは、2 つのセッションが異なる値を取得することを保証し、シリアル化は必要ありません。パフォーマンスが向上し、安全性が向上し、コーディングが容易になり、保守が容易になります。

シーケンスを使用して重複エラーが発生する唯一の方法は、シーケンス値を超える ID を持つレコードがテーブルに既に存在する場合、またはシーケンスを使用せずに何かがまだレコードを挿入している場合です。したがって、たとえば 1 から 10 までの ID が手動で入力された既存のテーブルがあり、デフォルトの start-with 値 1 でシーケンスを作成した場合、シーケンスを使用した最初の挿入では ID 1 を挿入しようとしますが、これは既に存在します。 . これを 10 回試行すると、シーケンスは 11 回になり、これでうまくいきます。次に max-ID アプローチを使用して 12 を使用する次の挿入を行った場合、シーケンスはまだ 11 のままであり、次に を呼び出したときにも 12 になりますnextval

シーケンスとテーブルは関係ありません。手動で生成された ID 値がテーブルに挿入された場合、シーケンスは自動的に更新されないため、2 つのアプローチが混在することはありません。(とりわけ、ドキュメントに記載されているように、同じシーケンスを使用して複数のテーブルの ID を生成できます)。

手動アプローチからシーケンス アプローチに変更する場合は、テーブル内の既存のすべての ID よりも大きい start-with 値でシーケンスが作成されていること、および挿入を行うすべての操作でシーケンスが使用されていることを確認する必要があります。将来的にのみ。

于 2013-06-20T10:13:02.233 に答える
10

複数のユーザーを使用する場合は、シーケンスを使用すると機能します。を使用maxしないでください。

a を実行し、max(id) + 1複数のユーザーを許可すると、同時に動作している複数のセッションが定期的に同じものを参照するmaxため、同じ新しいキーが生成されます。制約を正しく構成したと仮定すると、処理する必要があるエラーが生成されます。INSERTセッションが再試行される前に他のセッションがあなたをブロックすると、何度も失敗する可能性がありますが、それはすべての操作に多くの余分なコードですINSERT

また、コードをシリアル化します。セッションに新しい行を挿入し、コミットする前に昼食に出かけた場合 (または、コミットする前にクライアント アプリケーションがクラッシュした場合)、他のすべてのユーザーは、私が戻ってコミットするか、またはDBA がセッションを強制終了し、強制的に再起動します。

于 2013-06-20T10:14:02.550 に答える
4

他の回答に追加するには、いくつかの問題があります。

テーブルにまだ行がない場合、 max(id)+1 構文も失敗するため、次を使用します。

Coalesce(Max(id),0) + 1

データ ウェアハウスのロードの場合のように、テーブルに挿入するプロセスが 1 つしかない場合、および max(id) が高速である場合 (おそらくそうである場合)、この手法に問題はありません。

また、たとえば復元データをテスト システムに移動する場合に、テーブルとシーケンスの間で値を同期するためのコードが不要になります。

以下を使用して、このメソッドを複数行挿入に拡張できます。

Coalesce(max(id),0) + rownum

ただし、並列挿入をシリアル化する可​​能性があると思います。

一部の手法は、これらの方法ではうまく機能しません。もちろん、それらは select ステートメントを発行できることに依存しているため、SQL*Loader は除外される可能性があります。ただし、SQL*Loader は、列仕様の SEQUENCE パラメータを通じて、この手法を一般的にサポートしています: http://docs.oracle.com/cd/E11882_01/server.112/e22490/ldr_field_list.htm#i1008234

于 2013-06-20T10:19:29.697 に答える
0

MAX(ID) が実際に十分に高速であると仮定すると、次のことが可能ではないでしょうか。

  • 最初にMAX(ID)+1を取得
  • 次に、NEXTVAL を取得します。
  • これら 2 つを比較し、NEXTVAL が MAX(ID)+1 より小さい場合はシーケンスを増やします
  • INSERT ステートメントで NEXTVAL を使用する

その場合、私は完全に安定した手順を持ち、シーケンスの更新を心配することなく手動挿入も許可されます

于 2013-06-28T10:27:05.997 に答える