Задать вопрос
@reddyk1

FOR UPDATE блокировка с неуникальным ключом?

Добрый день.
Столкнулся со следующей проблемой. В базе содержаться адреса пользователей

| id | addr | ... | status
....

Собственно, хочу чтобы несколько экземпляров скрипта запускались, брали записи и производили определенные манипуляции, где status = 1.

SELECT * FROM table where status = 1 limit 50 for update skip locked

В этом случае блокируется все записи где status = 1, limit никак не помогает.

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

SELECT * FROM table where id = 1 for update

Как быть если нужно делать выборку по status? Юзать redis? Плодить поля типа process_id, locked и тд в базе не хочу.

update!
Сейчас понял что забыл закомментить строку с orderBy. И как оказалось проблема конкретно в этом.
For update при любом условии и orderby блокирует все записи которые подходят под это условие.

UPD v2.
Итак, проблема была в индексах. При блокировке c условием по индексам запрос выполняется с использованием алгоритма объединения индексов https://dev.mysql.com/doc/refman/5.7/en/index-merg... .
Выходов как я понял несколько: FORCE INDEX, либо создать индекс поверх используемых. Я воспользовался самым простым не особо критичным для меня и удалил индексы.
  • Вопрос задан
  • 107 просмотров
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 2
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
По одной строки можно выбирать так:
SET @id = 0;

UPDATE `table`
  SET `status` = 2
  WHERE (@id := `id`) AND `status` = 1
  LIMIT 1;

SELECT *
  FROM `table`
  WHERE `id` = @id;

UPDATE - операция атомарная, она одновременно меняет статус строки и записывает в переменную @id идентификатор этой строки.
Ответ написан
@Siverius
SELECT * FROM table
WHERE id IN (SELECT id FROM table where status = 1 limit 50) 
for update skip locked


А если так?
Ответ написан
Ваш ответ на вопрос

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

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