Рекомендации по многопоточной обработке записей в базе данных
У меня есть один процесс, который запрашивает таблицу для записей, где PROCESS_IND
= 'N', выполняет некоторую обработку, а затем обновляет PROCESS_IND
до 'Y'.
Я хотел бы разрешить запуск нескольких экземпляров этого процесса, но не знаю, какие рекомендации лучше избегать проблем concurrency.
С чего начать?
Ответы
Ответ 1
Образец, который я использовал бы, выглядит следующим образом:
- Создайте столбцы "заблокирован" и "время блокировки", которые являются идентификатором потока/процесса/машины и меткой времени соответственно (вам понадобится идентификатор машины, когда вы разделите обработку между несколькими машинами).
-
Каждая задача будет выполнять запрос, например:
UPDATE taskstable SET lockedby = (мой id), locktime = now() ГДЕ заблокировано IS NULL ORDER BY ID LIMIT 10
Где 10 - "размер партии".
- Затем каждая задача выполняет SELECT, чтобы выяснить, какие строки она "заблокирована" для обработки, и обрабатывает эти
- После того, как каждая строка будет завершена, вы установите блокировку и время блокировки обратно на NULL
- Все это делается в цикле для как можно большего количества пакетов.
- Задача cron или запланированное задание периодически сбрасывает "заблокированную" любую строку, время блокировки которой слишком давно, так как они предположительно выполнялись заданием, которое зависало или разбилось. Затем кто-то другой подберет их.
LIMIT 10 имеет специфику MySQL, но я думаю, что другие базы данных имеют эквиваленты. ORDER BY импортируется, чтобы избежать неопределенности запроса.
Ответ 2
Хотя я понимаю намерение, я бы не согласился сразу на блокировку уровня строки. Это уменьшит время отклика и может ухудшить вашу ситуацию. Если после тестирования вы видите проблемы с concurrency с APL, вы должны сначала выполнить итеративный переход к блокировке "datapage"!
Чтобы действительно ответить на этот вопрос, потребуется больше информации о структуре таблицы и задействованных указателях, но для дальнейшего объяснения.
DOL, блокировка datarow использует намного больше блокировок, чем блокировка уровня страницы/страницы. Накладные расходы при управлении всеми замками и, следовательно, уменьшение доступной памяти из-за запросов на дополнительные блокировки в кеше снижают производительность и противодействуют любым достижениям, которые могут возникнуть при переходе к более параллельному подходу.
Проверяйте свой подход без перехода сначала на APL (блокировка всех страниц) по умолчанию, а затем, если проблемы видны, перейдите в DOL (сначала datapage, затем datarow). Имейте в виду, что при переключении таблицы в DOL все ответы в этой таблице становятся немного хуже, таблица использует больше места, и таблица становится более подверженной фрагментации, которая требует регулярного обслуживания.
Итак, коротко не переходите к datarows прямо, сначала попробуйте ваш подход concurrency, затем, если есть проблемы, используйте блокировку данных, а затем последний datarows.
Ответ 3
Вы должны включить row level locking
в таблице с помощью:
CREATE TABLE mytable (...) LOCK DATAROWS
Затем вы:
- Начать транзакцию
- Выберите строку с опцией
FOR UPDATE
(которая заблокирует ее)
- Делай все, что хочешь.
Никакой другой процесс не может сделать ничего с этой строкой до завершения транзакции.
Р. S. Некоторые из них касаются служебных задач, которые могут возникнуть в результате использования LOCK DATAROWS
.
Да, есть накладные расходы, хотя я вряд ли назвал бы это проблемой для таблицы, подобной этой.
Но если вы переключитесь на DATAPAGES
, вы можете заблокировать только одну строку за PAGE
(2k
по умолчанию), а процессы, строки которых находятся на одной странице, не смогут работать одновременно.
Если мы говорим о таблице с дюжиной строк, которые будут заблокированы сразу, вряд ли будет заметное снижение производительности.
Процесс concurrency имеет гораздо большее значение для такого дизайна.
Ответ 4
Наиболее очевидным способом является блокировка, если в вашей базе данных нет блокировок, вы можете реализовать ее самостоятельно, добавив поле "Заблокировано".
Некоторые из способов упрощения concurrency - рандомизировать доступ к необработанным элементам, поэтому вместо конкуренции по первому элементу они распределяют доступ случайным образом.
Ответ 5
Преобразуйте процедуру в один оператор SQL и обработайте несколько строк как одну партию. Вот как должны работать базы данных.