Увеличение последовательности Oracle на определенную величину - PullRequest
5 голосов
/ 01 июля 2011

Я программирую приложение Windows (в Qt 4.6), которое - в какой-то момент - вставляет любое количество наборов данных от 1 до 76000 в некоторую таблицу оракула (10.2). Приложение должно извлечь первичные ключи или, по крайней мере, диапазон первичных ключей, из последовательности. Затем он сохранит идентификаторы в списке, который используется для пакетного выполнения подготовленного запроса.

(Примечание: триггеры не должны использоваться, а последовательность используется и другими задачами)

Чтобы не вызывать последовательность X раз, я бы хотел вместо этого увеличить последовательность на X.

На данный момент я выяснил, что в процедуре возможен следующий код:

ALTER SEQUENCE my_sequence INCREMENT BY X;

SELECT my_sequence.CURVAL + 1, my_sequence.NEXTVAL
INTO   v_first_number, v_last_number
FROM   dual;

ALTER SEQUENCE my_sequence INCREMENT BY 1;

У меня есть две основные проблемы:

  1. Я читал, что ALTER SEQUENCE производит неявный коммит. Означает ли это, что транзакция, запущенная приложением Windows, будет зафиксирована? Если да, можете ли вы как-то избежать этого?
  2. Является ли эта концепция многопользовательской? Или может произойти следующее:

    Sequence is at 10,000
    Session A sets increment to 2,000
    Session A selects 10,001 as first and 12,000 as last
    Session B sets increment to 5,000
    Session A sets increment to 1
    Session B selects 12,001 as first and 12,001 as last
    Session B sets increment to 1
    

    Даже если бы процедура была довольно быстрой, в моем приложении не исключено, что два разных пользователя вызывают вызов процедуры почти одновременно

Ответы [ 4 ]

5 голосов
/ 01 июля 2011

1) ALTER SEQUENCE - это DDL, поэтому он неявно фиксируется до и после оператора.Транзакция базы данных, запущенная приложением Windows, будет зафиксирована.Если вы используете координатор распределенных транзакций, отличный от базы данных Oracle, надеюсь, координатор транзакций зафиксирует всю распределенную транзакцию, но у координаторов транзакций иногда возникают проблемы с выданными коммитами, о которых он не знает.Вы ничего не можете сделать, чтобы предотвратить фиксацию DDL.

2) Сценарий, который вы описали для нескольких пользователей, вполне возможен.Так что не похоже, чтобы этот подход вел себя правильно в вашей среде.

Вы могли бы потенциально использовать пакет DBMS_LOCK, чтобы гарантировать, что только одна сессия вызывает вашу процедуру в любой момент времени, а затем вызватьпоследовательность N раз из одного оператора SQL.Но если другие процессы также используют последовательность, нет гарантии, что вы получите непрерывный набор значений.

CREATE PROCEDURE some_proc( p_num_rows IN NUMBER,
                            p_first_val OUT NUMBER,
                            p_last_val  OUT NUMBER )
AS
  l_lockhandle       VARCHAR2(128);
  l_lock_return_code INTEGER;
BEGIN
  dbms_lock.allocate_unique( 'SOME_PROC_LOCK',
                             l_lockhandle );
  l_lock_return_code := dbms_lock.request( lockhandle => l_lockhandle,
                                           lockmode => dbms_lock.x_mode,
                                           release_on_commit => true );
  if( l_lock_return_code IN (0, 4) ) -- Success or already owned
  then
    <<do something>>
  end if;

  dbms_lock.release( l_lockhandle );
END; 
4 голосов
/ 01 июля 2011

Изменение последовательности в этом сценарии действительно плохая идея.Особенно в многопользовательской среде.Вы получите совершенную транзакцию и, возможно, несколько ошибок в данных о состоянии гонки или ошибки целостности.Было бы целесообразно, если вы уже импортировали устаревшие данные и хотите вставить новые данные с идентификаторами из последовательности.Затем вы можете изменить последовательность, чтобы переместить currval к ​​максимально существующему ...

Мне кажется, что здесь вы хотите генерировать идентификаторы из последовательности.Это не нужно делать с помощью

select seq.nextval into l_variable from dual;
insert into table (id, ...) values (l_variable, ....);

. Вы можете использовать последовательность непосредственно во вставке:

insert into table values (id, ...) values (seq.nextval, ....);

и при желании получить назначенное значение обратно на

insert into table values (id, ...) values (seq.nextval, ....)
returning id into l_variable;

Это, конечно, возможно даже для массовых операций с execBatch.Либо просто создавая идентификаторы, либо даже возвращая их.Я не уверен насчет правильного синтаксиса в java, но это будет что-то в строках

insert into table values (id, ...) values (seq.nextval, ....)
returning id bulk collect into l_cursor;

, и вам будет предоставлен ResultSet для просмотра назначенных номеров.

2 голосов
/ 22 сентября 2015

В Oracle вы можете использовать следующий запрос, чтобы получить следующие N значений из последовательности, которая увеличивается на единицу:

выбор уровня, PDQ_ACT_COMB_SEQ.nextval как seq из двойного соединения по уровню <= 5; </p>

2 голосов
/ 01 июля 2011
  1. Вы не можете предотвратить неявную фиксацию.

  2. Ваше решение не является многопользовательским.Вполне возможно, что другой сеанс «восстановит» приращение до 1, как вы описали.

Я бы посоветовал вам продолжать извлекать значения одно за другим из последовательности, сохранитеИдентификаторы один за другим в вашем списке, и пакетное выполнение работает с этим списком.

По какой причине вы хотите получить непрерывный блок значений из последовательности?Я бы не слишком беспокоился о производительности, но, возможно, есть и другие требования, о которых я не знаю.

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