|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
FB 2.5 Есть таблица, назначение которой - хранить очередь заданий, с такой структурой: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Что делает приложение по обработке таких заданий: 1) Открывается читающая транзакция, запрашивается 1 самая старая не взятая еще в работу задача: Код: plaintext 1. 2. 3. 4. 5.
2) Закрывается читающая транзакция и тут же открывается пищущая, в которой взятая в работу задача (с полученным на вышеописанном шаге ID) помечается как взятая в работу: Код: plaintext 1. 2.
Все элементарно, логично и когда эти задания обрабатывает 1 или 2-3 программы-клиентов - то все работает нормально. Однако 2-3 программы-клиента не успевают обрабатывать весь поток заданий в необходимое время, поэтому экспериментальным путем было получено, что таких программ необходимо иметь около 12-16. В таком случает все тоже работает бОльшую часть времени нормально, но встречаются случаи, когда из нескольких десятков заданий, какое-то одно могут взять одновременно 2 клиента. Т.е. может так совпасть, что за те несколько миллисекунд между 1 и 2 действием (взяли ID задачи, пометили ее) может отработать шаг "взяли ID задачи" на другом клиенте и тогда одна и та же задача выполнится дважды - а это проблема. Если эти 2 действия (SELECT+UPDATE одной и той же записи) оформить в виде одной ХП, то возникает lock-конфликт, хотя может быть я не разобрался с параметрами транзакции, в которой надо запускать такую ХП. Подскажите, как лучше реализовать подобную задачу? ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 12:38 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
SELECT FOR UPDATE WITH LOCK если обломился, знач кто-то уже успел раньше. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 12:44 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Даниил, во-первых дата-время для определения самой старой задачи плохой вариант. У тебя же ID автоинкремент вот и ориентируйся по нём. во-вторых научись обрабатывать конфликты обновления у себя в приложении ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 12:44 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Даниил, читать про SELECT WITH LOCK ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 12:46 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Даниил, можно по всякому. Начать с того, что lock conflict возникает при апдейте уже модифицируемой записи, поэтому комбинация select + update в процедуре ну никак не может такое вызывать, если такую процедуру запустить в монопольном режиме. Масса таких процедур одновременно будет вызывать те же самые lock conflict, что и просто масса update. Один из вариантов - в транзакции read committed rec_version nowait читать и делать update, если update конфликтует, перечитать еще раз, вероятно запись уже взята в работу и ее апдейтить бессмысленно. Собственно, у всей задачи приоритет один - успевает только первый апдейт, остальные получая lock conflict НЕ должны пытаться обработать эту запись. Другой вариант - выстроить транзакции в очередь. Стартовать транзакцию consistency wait с резервированием tasks в protected режиме, в транзакции select, update, commit. Можно было бы еще замутить read committed no_rec_version, но тут, возможно, придется "долбить" перечитыванием, если первая же запись уже модифицируется. Если читать поп. литературу, то искать надо "очереди в рсубд". ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 12:53 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
UPDATE RETURNING и никаких SELECT'ов Ну и обрабатывать конфликты обновления, это не сложно ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 12:56 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Понял, спасибо. Конфликты обновления будут обрабатываются в дальнейшем в рабочей версии, но в тестовом режиме хотел сначала разобраться с причиной их возникновения. Думал, что можно сделать вообще без конфликтов. Почитаю и, возможно, попробую оба варианта UPDATE RETURNING и SELECT FOR UPDATE WITH LOCK. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 13:36 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
hvladНу и обрабатывать конфликты обновления, это не сложно Обрабатывать - не сложно. Сложно придумать как именно обрабатывать. Раз очередь, значит надо бы пропускать заблокированные записи, но UPDATE RETURNINIG неспособна пропускать их самостоятельно и неспособна вернуть данные, необходимые для выборки "следующей" записи. PS: В конечном итоге афтар, надеюсь, таки придёт к единственному диспетчеру заданий вместо 10-12, ибо "другой альтернативы - нет". Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 13:55 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Dimitry SibiryakovhvladНу и обрабатывать конфликты обновления, это не сложно Обрабатывать - не сложно. Сложно придумать как именно обрабатывать. Раз очередь, значит надо бы пропускать заблокированные записи, но UPDATE RETURNINIG неспособна пропускать их самостоятельно и неспособна вернуть данные, необходимые для выборки "следующей" записи. UPDATE RETURNINIG будет заниматься обработкой только 1 записи. "Следующая" запись уже будет обрабатываться в другой транзакции. Все возникающие lock conflict при этом - просто игнорируем (понимая, что какой-то другой обработчик уже работает с этой записью). Я пока так логику понял. Dimitry SibiryakovPS: В конечном итоге афтар, надеюсь, таки придёт к единственному диспетчеру заданий вместо 10-12, ибо "другой альтернативы - нет". Пока придумывается для единственного диспетчера - это раздача заданий обработчикам на этапе их создания (триггер на INSERT, либо каким-то приложением-клиентом). После чего обработчики берут из очереди только "свои" задания и не конфликтуют друг с другом. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 14:08 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Даниил"Следующая" запись уже будет обрабатываться в другой транзакции. Все возникающие lock conflict при этом - просто игнорируем (понимая, что какой-то другой обработчик уже работает с этой записью). Я пока так логику понял. Не будет оно так работать. Лучшее, на что ты можешь рассчитывать: читать обычным select, каждую прочитанную запись пробовать update и так до тех пор пока записи не кончатся или update не будет успешным. Достаточно одной транзакции. Работать будет если последовательность обработки заданий не важна. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 14:15 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Даниил, select for update with lock работать не будет, потому что он будет блокировать сразу несколько выбираемых записей, и вся система встанет крабом. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 14:40 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
28.03.2019 14:40, kdv пишет: > select for update with lock работать не будет, потому что он будет блокировать сразу несколько выбираемых записей, и вся система встанет крабом. select for update with lock всегда выбирает по одной. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 15:48 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Dimitry SibiryakovhvladНу и обрабатывать конфликты обновления, это не сложно Обрабатывать - не сложно. Сложно придумать как именно обрабатыватьОткат + повтор, классика. Какие проблемы ? Если нагрузка по самое нехочу (100500 рабочих одновремено выгребают эту очередь), то можно добавить рандомный таймаут между попытками. Но для такой нагрузки нужны другие методы, а не общая очередь. Dimitry Sibiryakovпропускать заблокированные записиС этим к другим, не к нам ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 16:02 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
можно использовать insert первичные ключи внетранзакционны. можно завести таблицу ACTIVE_TASK(ID), второй при попытке вставки обломается ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 17:48 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Мимопроходящийselect for update with lock всегда выбирает по одной. у него запрос select first 1, тогда вроде ок. Хотя, если order by будет PLAN SORT, то что-то я не уверен, что не заблокируются все записи, слитые в sort. При sort записи-то выбираются не из базы. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.03.2019, 18:54 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
не. он блокирует только то, что выдал. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2019, 12:00 |
|
SELECT и UPDATE одной записи таблицы в одной транзакции
|
|||
---|---|---|---|
#18+
Мимопроходящий, уговорил. Вообще я напомню, что select first 1 ... order by non_indexed_field приводит к PLAN SORT, и сортирует ВЕСЬ набор записей, и только потом выдает одну запись (в отличие от plan order). Поскольку все столбцы у запроса с plan sort уже в файле сортировки, сервер в базу за записями не лезет. Отсюда я сделал предположение, что у такого запроса с with lock будет блокировка по всем записям, независимо от того, сколько записей выдано по FIRST. Оказалось, что я неправ. Проверил так: 1. выдаем с одного клиента запрос Код: sql 1. 2. 3.
2. со второго клиента выдаем то же самое, получаем lock conflict on no wait transaction. Тут понятно, борьба за первую одинаковую запись. 3. Но, если со второго клиента выдаем Код: sql 1. 2. 3. 4.
то есть, НЕ ТУ запись, которую выдал первый запрос. Ошибки нет, всё норм. ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2019, 16:55 |
|
|
start [/forum/topic.php?fid=40&msg=39793507&tid=1560767]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
74ms |
get topic data: |
9ms |
get forum data: |
3ms |
get page messages: |
56ms |
get tp. blocked users: |
1ms |
others: | 300ms |
total: | 473ms |
0 / 0 |