Есть ли более быстрый способ обновить самую старую строку таблицы MySQL, которая соответствует определенному условию, чем использование ORDER BY id LIMIT 1
, как в следующем запросе?
UPDATE mytable SET field1 = '1' WHERE field1 = 0 ORDER BY id LIMIT 1;
Примечание:
- Предположим, что первичный ключ —
id
, а также есть индексfield1
. - Мы обновляем одну строку.
- Мы не обновляем самую старую строку строго, мы обновляем самую старую строку, соответствующую условию.
- Мы хотим обновить самую старую совпадающую строку, т. е. самую нижнюю
id
, т. е. начало очереди FIFO.
Вопросы:
ORDER BY id
обязательно? Как MySQL упорядочивает по умолчанию?
Пример реального мира
У нас есть таблица БД, используемая для очереди электронной почты. Строки добавляются, когда мы хотим поставить электронные письма в очередь для отправки нашим пользователям. Строки удаляются заданием cron, которое запускается каждую минуту, обрабатывая как можно больше за эту минуту и отправляя 1 электронное письмо на строку.
Мы планируем отказаться от этого подхода и использовать что-то вроде Gearman или Resque для обработки нашей очереди электронной почты. Но в то же время у меня есть вопрос о том, как мы можем эффективно пометить самый старый элемент очереди для обработки, также известный как строка с самым низким идентификатором. Этот запрос выполняет задание:
mysql_query("UPDATE email_queue SET processingID = '1' WHERE processingID = 0 ORDER BY id LIMIT 1");
Тем не менее, он часто появляется в медленном журнале mysql из-за проблем с масштабированием. Запрос может занять более 10 секунд, если в таблице 500 000 строк. Проблема в том, что эта таблица сильно разрослась с тех пор, как была впервые представлена, и теперь иногда имеет полмиллиона строк и накладные расходы в 133,9 МБ. Например, мы ВСТАВЛЯЕМ 6000 новых строк примерно 180 раз в день и УДАЛЯЕМ примерно столько же.
Чтобы запрос не появлялся в медленном журнале, мы удалили ORDER BY id
, чтобы остановить массовую сортировку всей таблицы. то есть
mysql_query("UPDATE email_queue SET processingID = '1' WHERE processingID = 0 LIMIT 1");
... но новый запрос больше не всегда получает строку с наименьшим идентификатором (хотя это часто бывает). Есть ли более эффективный способ получить строку с наименьшим идентификатором, кроме использования ORDER BY id
?
Для справки, это структура таблицы очереди электронной почты:
CREATE TABLE IF NOT EXISTS `email_queue` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time_queued` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time when item was queued',
`mem_id` int(10) NOT NULL,
`email` varchar(150) NOT NULL,
`processingID` int(2) NOT NULL COMMENT 'Indicate if row is being processed',
PRIMARY KEY (`id`),
KEY `processingID` (`processingID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;