powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Оптимизация параллельной выборки
10 сообщений из 10, страница 1 из 1
Оптимизация параллельной выборки
    #39987091
e_moon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Приветствую, уважаемые разработчики!
Спасибо за ваше внимание к моему вопросу!

У меня есть таблица, в которую постоянно помещается очередь заданий для обработки:

TABLE "users_activity" (MyISAM)
"id" (INT 11) PRIMARY KEY,
"action" (VARCHAR 50),
"flag" (INT 1) INDEX

Здесь "action" - это просто название обработчика (функции), который нужно произвести (обрезка загруженного видео, оптимизация фотографии и т.п.)

А "flag" может быть 0 - задание в очереди, 1 - обрабатывается в данный момент, 2 - готово.

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

1. Выбирает запись и ставит флаг "в обработке" (чтобы предотвратить параллельное выполнение задачи, которое уже в очереди).

Код: sql
1.
UPDATE user_activity SET flag=2 WHERE id=(@cur_value_13994_82fd7dfbeeef870b654ee9bfa7244713 := (SELECT * FROM (SELECT id FROM user_activity WHERE id>=298122 AND flag=0 ORDER BY id LIMIT 1) AS tmp));


2. Обрабатывает

3. И обновляет флаг, что задача завершена.
Код: sql
1.
UPDATE user_activity SET flag=1 WHERE id=@cur_value_13994_82fd7dfbeeef870b654ee9bfa7244713


Проблема в том, что 1 запрос на выборку уникальной очередной записи часто подвисает на 5-7 секунд.
Код: sql
1.
UPDATE user_activity SET flag=2 WHERE id=(@cur_value_13994_82fd7dfbeeef870b654ee9bfa7244713 := (SELECT * FROM (SELECT id FROM user_activity WHERE id>=298122 AND flag=0 ORDER BY id LIMIT 1) AS tmp));


id>=298122 - для ускорения запроса сохраняю каждый последний успешный id и добавляю его в подзапрос SELECT.

Кроме того, в самой таблице ранее выполненные (flag=1) задания регулярно удаляются, т.е. количество строк в таблице не является безграничным, поддерживается в диапазоне 0-3000 строк одновременно.

Но увы...

Код: sql
1.
# Query_time: 6.250778  Lock_time: 3.121639  Rows_sent: 0  Rows_examined: 1417


Ищу любые идеи оптимизации...
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987095
Фотография ScareCrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторRows_examined: 1417
индексов нет?
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987105
e_moon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ScareCrow,
"id" (INT 11) PRIMARY KEY,
"flag" (INT 1) INDEX
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987108
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
e_moon
"flag" может быть 0 - задание в очереди, 1 - обрабатывается в данный момент, 2 - готово.
Плохо. А ну как два обработчика захотят "ухватить" себе одно и то же задание?

Я бы сделал:

Каждый обработчик регистрируется в системе, получая уникальный номер, и потом уже работает. В поле флага:

NULL - задание в очереди,
0 - задание обработано,
больше нуля - идентификатор обработчика, который обрабатывает задание в данный момент.

Соответственно резервирование выполняется простейшим

Код: sql
1.
2.
3.
4.
UPDATE user_activity 
SET flag = @идентификатор_обработчика
WHERE flag IS NULL
LIMIT 1



После чего зарезервированное задание забирается на обработку

Код: sql
1.
2.
3.
SELECT id 
FROM user_activity 
WHERE flag = @идентификатор_обработчика



Если идентификатор задания получен - обрабатываем.
Если же произойдёт одновременное резервирование, и задание будет "перехвачено" (записанное значени flag перезаписано параллельным запросом), второй запрос не вернёт записи, и обработчик снова попробует зарезервировать себе запись.

e_moon
Проблема в том, что 1 запрос на выборку уникальной очередной записи часто подвисает на 5-7 секунд.

А что Вы хотите? MyISAM - так что каждый из запросов лочит всю таблицу. Перейдите на InnoDB.
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987135
e_moon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,

Спасибо за подробный ответ!

Честно говоря, я был уверен что делаю то же самое, только обернуто в один запрос. Выбираю запись и запоминаю ее id, дальше обновляю флаг по этому id. Т.к. MyISAM не поддерживает транзакции, то это единственный выход, который я нашел.

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

Но по поводу InnoDB... У меня сейчас есть другая сторона медали - это еще INSERT-ы в эту таблицу. В MyISAM есть возможность INSERT DELAYED IGNORE, но в InnoDB, похоже, этого нет. Обычный INSERT в случае InnoDB не будет тормозить?
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987231
e_moon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Да, еще добавил составной индекс:
Код: sql
1.
UNIQUE KEY `flag_id` (`flag`,`id`)


Но разницы не заметно:(
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987385
Фотография ScareCrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
сильон вряд ли такой индекс будет использоваться. смотри планы запроса.
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987409
paver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ScareCrow
сильон вряд ли такой индекс будет использоваться. смотри планы запроса.

Кстати, да. А вот с обратным порядком полей (id, flag) для запроса
Код: sql
1.
SELECT id FROM user_activity WHERE id>=298122 AND flag=0 ORDER BY id LIMIT 1

индекс будет вполне полезным, да еще и покрывающим.
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39987450
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
paver
А вот с обратным порядком полей (id, flag) для запроса
Код: sql
1.
SELECT id FROM user_activity WHERE id>=298122 AND flag=0 ORDER BY id LIMIT 1


индекс будет вполне полезным, да еще и покрывающим.
Как раз для ЭТОГО запроса (`flag`,`id`) гораздо полезнее - но его надо форсить, ибо селективность префикса хреновая.

Правда, запрос при этом надо конвертировать в
Код: sql
1.
SELECT MIN(id) id FROM user_activity WHERE id>=298122 AND flag=0
...
Рейтинг: 0 / 0
Оптимизация параллельной выборки
    #39990563
e_moon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо всем за помощь.
Финальный SQL:
Код: sql
1.
SELECT id FROM user_activity WHERE id>=298122 AND flag=0 LIMIT 1


Explain показывает Range.
В общем, убрав только ORDER BY удалось добиться хорошего результата и скорости. В принципе, в моем случае очередность не столь критична и этим удалось пренебречь.
Код: sql
1.
MIN(id)


Как ни странно, но вариант с MIN(id) оказался хуже, Explain показывает All. Но для теста я его оставил и он вызывается 1 на 100 интераций где-то, попробую его тоже поотслеживать на деле и сравню, когда будут данные.
...
Рейтинг: 0 / 0
10 сообщений из 10, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Оптимизация параллельной выборки
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]