2010-05-28 6 views
4

Я использую таблицу с счетчиком, чтобы обеспечить уникальный идентификатор дочернего элемента.Oracle (PL/SQL): UPDATE RETURNING одновременно?

Я знаю, что лучше использовать последовательность, но я не могу использовать ее, потому что у меня много счетчиков (клиент может создать пару ковшей, и каждый из них должен иметь свой счетчик, они должны начать с 1 (это требование, мой клиент нуждается в «человеческий читаемый» ключи).

Я создаю записи (давайте называть их элементы), которые имеют prikey (bucket_id, Num = счетчик).

Мне нужно гарантировать, что комбинация bucket_id/num уникальна (так что использование последовательности как prikey не устранит мою проблему).

Создание ro ws не происходит в pl/sql, поэтому мне нужно потребовать номер (кстати, это не противоречит требованиям наличия пробелов).

Мое решение было:

UPDATE bucket 
     SET counter = counter + 1 
    WHERE id = param_id 
RETURNING counter INTO num_forprikey; 

PL/SQL возвращает var_num_forprikey поэтому запись пункт может быть создан.

Вопрос:

Будет ли всегда получить уникальный num_forprikey, даже если пользователь одновременно запрашивает для новых деталей в ведре?

+0

Я так думаю, но я не могу найти документацию об этом !! – Jaap

ответ

6

Будет ли всегда получить уникальный num_forprikey , даже если пользователь одновременно запрашивает новых товаров в ковше?

Да, по крайней мере, до точки. Первый пользователь, который выдает это обновление, получает блокировку в строке. Таким образом, ни один другой пользователь не может успешно выполнить этот же оператор до тех пор, пока пользователь numero uno не совершит (или откатится). Поэтому уникальность гарантирована.

Очевидно, что придирка касается параллелизма. Ваш доступ к строке сериализуется, поэтому нет возможности для двух пользователей одновременно получать новый PRIKEY. Это не обязательно проблема. Это зависит от того, сколько пользователей вы создаете новые элементы и как часто они это делают. Один пользователь, снимающий номера в одном сеансе, ничего не заметит.

+3

APC говорит правду. Тем не менее, это отличный способ приостановить работу вашего приложения, если сеанс не COMMIT обновления. –

0

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

http://www.orafaq.com/forum/t/83382/0/ Выгоды для последовательностей (и они могут быть динамически созданы, что вы можете указать NoCache и гарантийный заказ)

+0

Каждое ведро должно иметь собственный счетчик, поэтому я не могу использовать последовательности! – Jaap

+0

Создание последовательностей динамически не является вариантом, потому что там будет много ведер ... – Jaap

1

Кажется, я вспоминаю эту проблему из многих лет назад, работая над всеми базами данных INGRES. В те дни не было никаких последовательностей, поэтому было затрачено много усилий на то, чтобы найти лучшее решение для масштабирования для этой проблемы с помощью лучших идей INGRES того дня. Мне посчастливилось работать вместе с ними так, что, хотя мой разум жалко меньше любого из них, proxmity = остаточный аффект, и я что-то сохранил. Это была одна из вещей. Позвольте мне посмотреть, помню ли я.

1) for each counter you need row in a work table. 
2) each time you need a number 
    a) lock the row 
    b) update it 
    c) get its new value (you use returning for this which I avoid like the plague) 
    d) commit the update to release your lock on the row 

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

В мире оракулов мы улучшили бы ситуацию, используя функцию, определенную как AUTONOMOUS_TRANSACTION, чтобы получить следующее число. Если вы думаете об этом, это решение требует разрешения пробелов, которые вы сказали в порядке. Приобретая обновление номера независимо от основной транзакции, вы получаете масштабируемость, но вы вводите пробелы.

Вам придётся принять тот факт, что масштабируемость резко снизится в этом сценарии. Это связано как минимум с двумя причинами:

1) последовательность обновления/выбора/фиксации делает все возможное, чтобы сократить время, в течение которого строка KEY заблокирована, но она по-прежнему не равна нулю. При большой нагрузке вы будете сериализоваться и в конечном итоге быть ограничены.

2) вы совершаете на каждом ключе. Конец - дорогостоящая операция, требующая много действий по управлению памятью и файлами со стороны базы данных. Это также ограничит вас.

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

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

Удачи. Я не тестировал код для синтаксических ошибок, я оставляю это вам.

create or replace function get_next_key (key_name_p in varchar2) return number is 
    pragma autonomous_transaction; 
    kev_v number; 
begin 

    update key_table set key = key + 1 where key_name = key_name_p; 

    select key_name into key_name_v from key_name where key_name = key_name_p; 

    commit; 

    return (key_v); 

end; 
/
show errors 
1

Вы все равно можете использовать последовательности, просто используйте аналитическую функцию row_number(), чтобы порадовать ваших пользователей. Я описал его здесь более подробно: http://rwijk.blogspot.com/2008/01/sequence-within-parent.html

С уважением, Роб.

Смежные вопросы