7

私はSpringとHibernateと協力して、JavaでWebアプリケーションを開発しています。私がテーブルを持っていると仮定しましょう。このテーブルからいくつかのレコードを削除すると、主キーフィールドの値をリセットする必要がある場合があります。

テーブルに10個のレコードがあり、最後の5個のレコードを削除するとします。これで、新しいレコードを挿入するときに、主キーフィールドの値はで開始する必要がありますが、6で開始し11ます。

MySqlの6( )で主キー値を開始する必要がある場合は、次のSQLステートメントを実行する必要があります。maximum +1

alter table table_name auto_increment=1;

auto_incrementこれにより、の値がそのフィールドの値に自動的にリセットされmaximum + 1ます(概念的には正しくない可能性がありますが、機能します)。

Oracle(10g)ではsequence、主キーを使用しています。一部のレコードがデータベースから削除されたときにtovalueの値sequenceをリセットする方法はOracleにありますか?maximum + 1

4

4 に答える 4

17

使用している場合に値をリセットしない理由:

20個のレコードがあり、5〜10個のレコードを削除するとどうなりますか?シーケンスを再設定しても解決されないギャップが途中にあります。数列は、ギャップのない数列、完全な1、2..nを生成することはありません。

呼び出し.nextvalて値を使用しない場合、値はなくなります。シーケンスを削除して再作成しますか?挿入を開始してキャンセルし、Oracleが行ったことをロールバックすると、これらの値は失われます。設定すると、ギャップは少なくなりますが、パフォーマンスが低下します。その価値はありますか?nocache

パフォーマンスの問題を回避するために、キャッシュは、すべてのセッションで一度に実行すると予想される挿入の数に設定する必要があります。シーケンスは、正の整数のセットを再生成しないように、ロックなどを使用せずに代理キーを作成する非常に迅速でスケーラブルな方法を提供するように設計されています。

結局のところ、それは少しでも問題ではないはずです。テーブルのキーとして途切れのないシーケンスに依存している場合は、シーケンスではなくデータに問題があります。


質問への回答:

実際にあなたの質問に答えるには、次のことを行う必要があります。

  1. まず、テーブル内の最大ID(シーケンス)値を確認します。
  2. 次に、シーケンスをドロップして再作成します

最大値を見つけることは、パフォーマンスへの別のヒットを犠牲にして、シーケンスを動的に再作成する必要があることを意味します。

これが発生しているときにテーブルに何かを挿入しようとすると、失敗し、次のシーケンスを使用するトリガーまたはその他のオブジェクトが無効になる可能性があります。

declare

   l_max_value number;

begin

   select max(id)
     into l_max_value
     from my_table;

   execute immediate 'drop sequence my_sequence_name';

   -- nocache is not recommended if you are inserting more than
   -- one row at a time, or inserting with any speed at all.
   execute immediate 'create sequence my_sequence_name
                           start with ' || l_max_value
                      || ' increment by 1
                           nomaxvalue
                           nocycle
                           nocache';

end;
/

私が言うように、これは推奨されておらず、ギャップを無視する必要があります。


更新-別名ジェフリーケンプのおかげでより良い答え:

ドキュメントの推奨に反して、Jeffrey Kempがコメントで提案したように、シーケンスを削除して再作成せずにこれを行う方法があります。

つまり、次のようになります。

  1. idテーブルの最大値とシーケンスの現在の値の差を計算します。
  2. この負の数で増分するようにシーケンスを変更する
  3. シーケンスを変更して、もう一度1ずつインクリメントします。

これの利点は、オブジェクトがまだ存在し、トリガー、付与などが引き続き維持されることです。欠点は、私が見ているように、別のセッションがあなたのセッションと同時にこの負の数だけ増加すると、行き過ぎてしまう可能性があることです。

これがデモンストレーションです:

テストを設定します。

SQL> create sequence test_seq
  2   start with 1
  3   increment by 1
  4   nomaxvalue
  5   nocycle
  6   nocache;

Sequence created.

SQL>
SQL> create table tmp_test ( id number(16) );

Table created.

SQL>
SQL> declare
  2     l_nextval number;
  3  begin
  4
  5    for i in 1 .. 20 loop
  6       insert into tmp_test values ( test_seq.nextval );
  7    end loop;
  8
  9  end;
 10  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        20

SQL>
SQL> delete from tmp_test where id > 15;

5 rows deleted.

SQL> commit;

Commit complete.

シーケンスを元に戻す

SQL>
SQL> declare
  2
  3     l_max_id number;
  4     l_max_seq number;
  5
  6  begin
  7
  8     -- Get the maximum ID
  9     select max(id) into l_max_id
 10       from tmp_test;
 11
 12     -- Get the current sequence value;
 13     select test_seq.currval into l_max_seq
 14       from dual;
 15
 16     -- Alter the sequence to increment by the difference ( -5 in this case )
.
 17     execute immediate 'alter sequence test_seq
 18                          increment by ' || ( l_max_id - l_max_seq );
 19
 20     -- 'increment' by -5
 21     select test_seq.nextval into l_max_seq
 22       from dual;
 23
 24     -- Change the sequence back to normal
 25     execute immediate 'alter sequence test_seq
 26                          increment by 1';
 27
 28  end;
 29  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        15

SQL>
于 2012-04-15T11:24:07.960 に答える
9

以下も機能します(シーケンス値が100増加します)。

select my_sequence.nextval from dual connect by level <= 100;
于 2013-04-02T14:09:07.997 に答える
6

OracleのALTERSEQUENCEドキュメントを参照すると、

  • 別の番号でシーケンスを再開するには、シーケンスを削除して再作成する必要があります。

次のシーケンス番号を生成するには、主キー列の現在の最大値を渡す必要があります。
最新のレコードを削除し続け、すでに生成されたシーケンス値を再利用したい場合は、このシーケンスを何度も再起動する必要があります。シーケンスをドロップすると、シーケンスを提供する準備が整う前にサーバーが次の値の要求を受信した場合にSQLExceptionが発生する可能性があります。

OracleSequencesに関する役立つメモもここにあります。

于 2012-04-15T06:30:09.467 に答える
0

このトリックは私のために働きます。私のシーケンス(USERSUTPL_USERUTPL_SQ)では、最後の番号は53でした。私のテーブルの最後のIDは83でした。

SELECT MAX(ID) FROM USERSUTPL_USERUTPL

次に、83-53=31です。

ALTER SEQUENCE USERSUTPL_USERUTPL_SQ INCREMENT BY +31;
SELECT USERSUTPL_USERUTPL_SQ.NEXTVAL FROM dual;
ALTER SEQUENCE USERSUTPL_USERUTPL_SQ INCREMENT BY 1;

そして、それは最後の数を変更します。:D

于 2016-09-15T01:56:35.313 に答える