Необходимо сбросить значение последовательности в 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
тогда у вас будет меньше пробелов, но за счет попадания в производительность; это того стоит?
ваш кэш должен быть установлен на количество вставок, которые вы ожидаете сделать в любой момент времени во всех сеансах чтобы избежать каких-либо проблем с производительностью. Последовательности конструированы для того чтобы обеспечить очень быстрое, масштабируемое способ создания суррогатных ключей без замков и т. д. не для повторного создания набора положительных целых чисел.
в конце концов это не имело ни малейшего значения. Если вы полагаетесь на непрерывную последовательность в качестве ключа вашей таблицы, у вас есть проблема с вашими данными, а не последовательностями.
отвечая на вопрос:
На самом деле ответить на ваш вопрос, вы должны:
- во-первых, узнайте каково максимальное значение id (последовательности) в вашей таблице.
- затем падение и воссоздание последовательности.
поиск максимального значения означает, что вам нужно будет динамически воссоздать последовательность за счет другого удара по производительности.
если вы попытаетесь вставить что-то в свою таблицу, пока это происходит, она потерпит неудачу и может аннулировать любые триггеры или другие объекты, которые используют последовательность:
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 лучший ответ благодаря Джеффри Кемп:
вопреки рекомендации документации есть, как Джеффри Кемп предложил в комментариях, способ сделать это без удаление и повторное создание последовательности.
а именно:
- разработка разницы между максимумом
id
в таблице и текущее значение последовательности. - изменение последовательности для увеличения на это отрицательное число
- изменение последовательности для увеличения на 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