Необходимо сбросить значение последовательности в Oracle

Я работаю с Spring и Hibernate для разработки веб-приложений на Java. Предположим, у меня есть столик. Когда я удалить некоторые записи из этой таблицы, Иногда мне нужно сбросить значение поля первичного ключа.

предположим, что у меня есть 10 записей в таблице, и я удаляю последние 5 записей. Теперь, когда я вставляю новые записи, значение поля первичного ключа должно начинаться с 6 но это начнется с 11.

если мне нужно начать значение первичного ключа в 6 (maximum +1) в MySql мне просто нужно выполнить следующий оператор SQL.

alter table table_name auto_increment=1;

это автоматически сбросит значение auto_increment to maximum + 1 значение этого поля (может быть концептуально неверным, но оно работает).

в Oracle (10g) я использую sequence с первичным ключом. Есть ли способ в Oracle сбросить значение sequence to maximum + 1 значение при удалении некоторых записей из базы данных?

4 ответов


причины, по которым вы не должны сбрасывать значение, если оно используется:

что произойдет, если у вас есть 20 записей и удалять записи 5-10? У вас есть пробел в середине, который повторная настройка последовательности не решит. Последовательность никогда создать пробел свободной последовательности чисел, совершенное 1, 2 .. n.

если вы называете .nextval и не используйте значение это ушел. Собираетесь ли вы отбросить и воссоздать последовательность? Если вы запустите insert и отмените его и 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;
/

как я сказал это не рекомендуется, и вы должны просто игнорировать любые пробелы.


Update-aka лучший ответ благодаря Джеффри Кемп:

вопреки рекомендации документации есть, как Джеффри Кемп предложил в комментариях, способ сделать это без удаление и повторное создание последовательности.

а именно:

  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>

также работает следующее (увеличивает значение последовательности на 100):

select my_sequence.nextval from dual connect by level <= 100;

со ссылкой на Oracle ИЗМЕНИТЬ ПОСЛЕДОВАТЕЛЬНОСТЬ документация

  • чтобы перезапустить последовательность на другом номере, вы должны упасть и воссоздайте его.

требуется передать текущее максимальное значение столбца первичного ключа, чтобы сгенерировать следующий порядковый номер.
Если вы продолжаете удалять последние записи и хотите повторно использовать уже созданные значения последовательности, может потребоваться перезапустить эту последовательность снова и снова. Падающий последовательность может привести к SQLException, если сервер получает запрос на следующее значение до того, как последовательность готова служить.

вы также можете найти некоторые полезные заметки о последовательностях Oracle здесь.


этот трюк работает для меня. В моей последовательности (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