Простой запрос MySQL занимает слишком много времени - PullRequest
1 голос
/ 07 апреля 2011

Среда: Rails 2.3.11, MySQL 5.1 (InnoDB)

В моем приложении Rails время от времени возникали проблемы с простыми запросами, выполнение которых занимало слишком много времени, а узкие места обновлялись. Эти запросы обычно относятся к форуму, разделу с самым высоким трафиком на сайте и к тому (с наибольшим количеством обновлений). Вот пример образца запроса, извлеченного из медленного журнала MySQL:

# Query_time: 46.900202  Lock_time: 0.000030 Rows_sent: 0  Rows_examined: 0
SET timestamp=1302172666;
UPDATE `forum_topics`
SET `views` = 153, `updated_at` = '2011-04-07 10:36:59'
WHERE `id` = 1213305;

Это очень простой запрос, который должен быть чрезвычайно быстрым, хотя в этом случае для его выполнения потребовалось почти 47 секунд. Средняя нагрузка на этот сервер никогда не превышает 2, так что это не проблема. Некоторые другие интересные объекты:

  • Ни views, ни updated_at не являются индексируются.
  • Хотя значение автоинкремента может быть 1.2M, есть на самом деле только 70K записей в этой таблице.
  • Более 90% всех запросов в журнале медленных запросов аналогичны этому.

Здесь я ищу несколько рекомендаций относительно следующих шагов, которые необходимо предпринять для решения этой проблемы.

Спасибо.

P.S. Схема / индексы следующие:

CREATE TABLE `forum_topics` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `forum_category_id` int(11) DEFAULT NULL,
  `title` varchar(255) NOT NULL,
  `sticky` tinyint(1) DEFAULT '0',
  `views` int(11) DEFAULT '0',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `last_post_created_at` datetime DEFAULT NULL,
  `slug` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_forum_topics_on_created_at` (`created_at`),
  KEY `index_forum_topics_on_forum_category_id` (`forum_category_id`),
  KEY `index_forum_topics_on_sticky` (`sticky`)
) ENGINE=InnoDB AUTO_INCREMENT=1215414 DEFAULT CHARSET=utf8;

Ответы [ 7 ]

1 голос
/ 09 апреля 2011

Есть много причин для внезапных остановок во многих продуктах баз данных - и MySQL не одинок.Вот несколько примеров:

  • Вам необходимо загрузить описание таблицы из хранилища (нет свободных записей кэша таблиц на forum_topics).Эта операция сериализована - вас могут поставить в очередь позади другого пользователя в другой таблице.

  • Вы используете кэш запросов, и кэш запросов (возможно) фрагментирован.

  • В настоящее время InnoDB выполняет действие, такое как увеличение размера файла данных, что вызывает короткую паузу (может быть, для auto_extend_increment установлено значение high?) ​​

Это просто примеры - причин, безусловно, больше.Что вам нужно сделать, это использовать инструмент профилирования, например, Profiler * бедного человека .Это даст вам трассировку стека относительно того, где именно запрос заблокирован.Поищите трассировку на bugs.mysql.com или попробуйте спросить что-то вроде форумов Percona .

1 голос
/ 07 апреля 2011

1) Возможно, произошла аппаратная ошибка - сброс диска.2) Индексируется ли ключ id?3) проблема связи.4) является ли временная метка локальной переменной?не должно ли быть «@» перед ним?

0 голосов
/ 09 января 2013

Это немного старо, но я наткнулся на него, и, может быть, это полезно для других ...

С такими проблемами вы можете использовать внутренний профилировщик:

mysql> SET PROFILING=1;
mysql> [your query]
mysql> SHOW PROFILE FOR QUERY 1;

Если ваша проблема возникает случайно, другой процесс мог заблокировать таблицу. Вы можете использовать SHOW FULL PROCESSLIST и SHOW OPEN TABLES, чтобы увидеть это.

Кроме того, с большими таблицами вы можете столкнуться с проблемами памяти для буферов - есть много хороших страниц об этом. http://dev.mysql.com/doc/refman/5.1/en/innodb-tuning.html и http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/ - отличное начало

0 голосов
/ 07 апреля 2011

Здесь недостаточно информации, чтобы точно сказать, почему ваш запрос медленно выполняется, но:

Если это таблица MYISAM, эти обновления могут занять очень много времени, поскольку в MYISAM отсутствует блокировка на уровне строк в таблицах. Это влияет на производительность вашего запроса, потому что каждый SELECT, который вам нужно запустить, получает READ LOCK для таблицы (не допуская дальнейших записей). Кроме того, UPDATE для таблицы MYISAM требует еще одной блокировки, которая блокирует запуск всех остальных UPDATES / INSERTS / SELECTS. Поэтому, если у вас было 10 таких запросов, они не работают одновременно и должны ждать завершения друг друга.

Я не думаю, что индексы - это ваша проблема, так как вы упомянули Автоинкремент и используете поле ID для своего обновления, поэтому я уверен, что это ваш первичный ключ.

0 голосов
/ 07 апреля 2011

Выполнение оптимизации для таблицы может помочь, особенно если на диске еще много удаленных строк.

Кроме того, что EXPLAIN в этом запросе показывает о том, как он выполняется (ну, в выбранной версииэтот запрос)

0 голосов
/ 07 апреля 2011

Предложение where обычно является виновником длительных запросов. Я вижу, что в этом запросе указывается только столбец id. Я бы проверил, проиндексировано ли оно. Если это так, я бы проверил, правильно ли он проиндексирован. Я бы даже попробовал переиндексировать столбец id, если для него уже есть индекс

0 голосов
/ 07 апреля 2011

Попробуйте добавить LIMIT к вашему запросу.Думаю, это должно выглядеть так:

... WHERE `id` = 1213305
    LIMIT 1
...