Существует ли более быстрый способ обновления самой старой строки таблицы 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 для обработки нашей почтовой очереди. Но в то же время у меня есть вопрос о том, как мы можем эффективно пометить самый старый элемент очереди для обработки, a.k.a. Строка с самым низким ID. Этот запрос выполняет работу:
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
, чтобы остановить массовую сортировку всей таблицы. т.е. * * 1 048
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;