Как выполнить запрос select и update с минимальной задержкой?

В общем задача:
Есть обработка данных, т.е. запрос к БД(с лимитом 100), потом некоторые операции с записями, update их. И что б не трогало их - присваивается ключ.
Так вот, если крон запустится и не успеет обработать все 100 записей, запускается следующий и начинают творить ад - некоторые строки считает дважды. Вначале один крон, потом другой. Хотя первый уже посчитал и все ок. Можно делать проверку при финальном запросе на upgrade, но тогда снижаем скорость - вначале все посчитается, а потом окажется, что считать не надо было.

Как сделать, что б при select получать ID и тут же присваивать ключ всем 100, а далее уже по очереди работать с этими записями?
Или как сделать, что б при работе кронов не создавался этот ад с данными?
  • Вопрос задан
  • 290 просмотров
Пригласить эксперта
Ответы на вопрос 5
devspec
@devspec
Помогло? Отметь решением
Не upgrade, а update.
Делайте в рамках одной транзакции.
Ответ написан
@Fortop
Tech/Team lead
Помимо транзакции, упомянутой выше можно ещё поставить блокировки на чтение.

Или же воспользоваться такой конструкцией как
SELECT ... FOR UPDATE

И третий случай уже не относящийся к Mysql - использовать системы очередей - Gearman, RabbitMQ
Ответ написан
Комментировать
dimonchik2013
@dimonchik2013
non progredi est regredi
ну крон-то не сам селектит, а пхп скриптом

ставьте флаг, если стоит - die() или что там вместо exit()
Ответ написан
Комментировать
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
А почему не обрабатывать по одной записи? Тогда можно делать захват строки атомарным запросом:
UPDATE `table` SET `updating` = NOW() WHERE ... AND `updating` IS NULL AND @id := `id` LIMIT 1;
SELECT * FROM `table` WHERE `id` = @id;

После обработки снова выставить `updating` на NULL. Периодически сбрасывать `updating` у строк, обработка которых продолжается слишком долго и, скорее всего, сбойнула.
При такой выборке параллельно обрабатывать строки может любое количество одинаковых скриптов.
Ответ написан
Комментировать
@entermix
Используйте транзакции

Блокируйте повторные запуски скрипта, если он уже/все еще в работе:
if (!flock($fh = fopen(__FILE__, 'r'), LOCK_EX | LOCK_NB)) die('Script is already running!');
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы