web-dev-qa-db-ja.com

Oracle:max(id)+1とsequence.nextvalの違い

Oracleを使用しています

max(id)+1を使用してIDを作成する場合と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レコードが重複しているというエラーが発生することがあります。

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

13
Priya Prajapati

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

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

シーケンスを使用して重複エラーを取得できる唯一の方法は、シーケンス値を超えるIDを持つレコードがテーブルにすでに存在する場合、またはシーケンスを使用せずにレコードを挿入している場合です。したがって、手動で入力されたID(1〜10など)を持つ既存のテーブルがあり、デフォルトの開始値が1のシーケンスを作成した場合、シーケンスを使用した最初の挿入では、すでに存在するID1が挿入されます。 。それを10回試した後、シーケンスは11になり、これは機能します。次に、max-IDアプローチを使用して、12を使用する次の挿入を実行した場合、シーケンスは11のままであり、次にnextvalを呼び出したときにも12になります。

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

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

34
Alex Poole

複数のユーザーがいる場合は、シーケンスの使用が機能します。 maxを使用することはできません。

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

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

10
Justin Cave

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

テーブルに行がまだない場合、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

4
David Aldridge

MAX(ID)が実際に十分に高速であると仮定すると、次のことは不可能です。

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

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

0
Stefanos Kargas