MySQL очень медленно работает с запросом DELETE, Apache странный во время выполнения запроса - PullRequest
6 голосов
/ 15 января 2011

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

  • База данных MySQL (5.1.50) на очень мощной (32 ядра процессора, 64 ГБ ОЗУ) машине FreeBSD 8.1-RELEASEна котором также работает Apache 2.2.
  • Apache получает в среднем около 50 обращений в секунду.Подавляющее большинство из этих хитов - это вызовы API для платформы продажи.
  • Вызовы API обычно генерируют результат примерно за полсекунды или меньше, но могут занять до 30 секунд в зависимости от сторонних производителей.
  • Каждый из вызовов API сохраняет строку в базе данных.Сохраненная там информация важна, но только в течение пятнадцати минут, после чего она должна истечь.
  • В таблице, в которой хранится информация о вызовах API (схема приведена ниже), InnoDB на уровне строкБлокировка используется для синхронизации между потоками (на самом деле соединения Apache), запрашивающими одну и ту же информацию в одно и то же время, что часто случается.Это означает, что несколько потоков могут ожидать блокировки строки до 30 секунд , поскольку вызовы API могут занять столько времени (но обычно этого не происходит).
  • Прежде всего, самое важное, что следует отметить, это то, что все работает идеально при нормальных обстоятельствах.

Тем не менее, это очень часто используемая таблица (пятьдесят или около того INSERT в секунду, много SELECT, используется блокировка на уровне строк) Я выполняю запрос DELETE:

CREATE TABLE `sales` (
  `sale_id` int(32) unsigned NOT NULL auto_increment,
  `start_time` int(20) unsigned NOT NULL,
  `end_time` int(20) unsigned default NULL,
  `identifier` char(9) NOT NULL,
  `zip_code` char(5) NOT NULL,
  `income` mediumint(6) unsigned NOT NULL,
  PRIMARY KEY  USING BTREE (`sale_id`),
  UNIQUE KEY `SALE_DATA` (`ssn`,`zip_code`,`income`),
  KEY `SALE_START` USING BTREE (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=FIXED

Запрос DELETE выглядит следующим образом и выполняется каждые пять минут в cron (я быпредпочитаю запускать его раз в минуту):

DELETE FROM `sales` WHERE 
    `start_time` < UNIX_TIMESTAMP(NOW() - INTERVAL 30 MINUTE);

Я использовал INT для поля времени, поскольку очевидно, что MySQL испытывает проблемы с использованием индексов с полями DATETIME.

Так вот в чем проблема: запрос DELETE, кажется, работает нормально большую часть времени (возможно, 7 из 10 раз).В других случаях запрос завершается быстро, но после этого MySQL, похоже, задыхается некоторое время.Я не могу точно доказать, что MySQL работает, но время появления симптомов определенно совпадает со временем выполнения этого запроса.Вот симптомы, когда все захлебывается:

  • При входе в MySQL и использовании SHOW FULL PROCESSLIST; выполняется всего несколько запросов INSERT INTO sales ..., где обычно болеесто.Что здесь ненормально, так это отсутствие каких-либо задач в списке процессов, а не их слишком много.Похоже, что MySQL прекращает принимать соединения полностью.
  • Проверяя состояние сервера Apache, Apache достиг MaxClients.Все потоки находятся в состоянии «Отправка ответа».
  • Apache начинает использовать много процессорного времени системы.Средние значения нагрузки увеличиваются, я видел средние значения нагрузки за 1 минуту до 100. Нормальное среднее значение нагрузки для этой машины составляет около 15. Я вижу, что она использует системный ЦП (в отличие от пользовательского ЦП), потому что я использую GKrellM для мониторингаit.
  • В top есть много процессов Apache, использующих много ЦП.
  • Веб-сайт и API (обслуживаемые Apache, конечно) в большинстве случаев недоступны.Некоторые запросы выполняются, но занимают около трех или четырех минут.Другие запросы отвечают через некоторое время с ошибкой «Не удается подключиться к серверу MySQL через /tmp/mysql.sock» - это та же ошибка, что и я, когда MySQL перегружен и имеет слишком много подключений (только это не такна самом деле говорят, что слишком много подключений).
  • MySQL принимает максимум 1024 подключений, mysqltuner.pl сообщает «[!!] Максимальное использование подключений: 100% (1025/1024)», что означает, что оно занято больше, чем ономог справиться в одной точке.Обычно при нормальных условиях существует не более нескольких сотен одновременных подключений MySQL.mysqltuner.pl не сообщает о других проблемах, я буду рад вставить вывод, если кто-нибудь захочет.

В конце концов, через минуту или две, все восстанавливается самостоятельно без какого-либо вмешательства.Загрузка ЦП возвращается к нормальной работе, Apache и MySQL возобновляют нормальную работу.

Итак, что я могу сделать? :) Как я могу начать расследовать, почему это происходит? Мне нужно , чтобы этот запрос DELETE выполнялся по разным причинам, почему дела идут плохо, когда он выполняется (но не всегда)?

1 Ответ

3 голосов
/ 15 января 2011

тяжелый.Это не ответ, а начало мозгового штурма.

Я бы сказал, может быть, проблема re-Index при удалении, в документе мы можем найти «быстро удалить», а затем«Оптимизировать таблицу», чтобы попытаться избежать слияния нескольких индексов.

Еще одна возможность, может быть также, это цепочка мертвых блокировок при удалении хотя бы с одним другим потоком, блокировки строкможет приостановить операцию удаления, а операция удаления может приостановить блокировку следующей строки.И тогда у вас есть либо обнаруженный тупик, либо необнаруженный, и происходит тайм-аут.Как вы обнаруживаете такие прерванные исключения параллелизма?Вы повторно запускаете свои транзакции?Если ваши потоки выполняют много разных блокировок строк в одних и тех же транзакциях, есть вероятность, что первая тупиковая ситуация повлияет на все больше и больше потоков (пробка).

Вы пытались заблокировать таблицу в транзакции удаления?Проверьте руководство, способ блокировки таблиц в транзакции в Innodb или получить общий доступ ко всем строкам.Возможно, вам понадобится некоторое время, чтобы получить таблицу только для вас, но если вы удалили достаточно быстро, никто не заметит, что вы взяли таблицу только для 1 с.

Теперь, даже если вы не пыталисьэто раньше, возможно, что делает удаление.Проверьте также этот документ о неявных блокировках , ваш запрос на удаление должен использовать индекс start_time, поэтому я вполне уверен, что ваше текущее удаление не блокирует все строки (не совсем уверен, что они блокируют все проанализированные строки нетолько строки, соответствующие условию where), но удаление вполне наверняка блокирует вставки.Приведены некоторые примеры взаимоблокировок с транзакциями, выполняющими удаление.Удачи!Для меня слишком поздно, чтобы понять все воздействия изоляции замка.

edit Вы можете попробовать изменить DELETE на UPDATE , установив удалено = 1 и выполните реальное удаление при малом времени использования (если оно есть).И измените клиентские запросы, чтобы проверить этот индексированный удаленный статус.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...