2009-08-10 2 views
3

У нас недавно была проблема, которую я никогда раньше не видел, где около 3 часов одна из наших таблиц Mysql была чрезвычайно медленной. Эта таблица содержит сообщения на форуме и в настоящее время содержит около миллиона строк. Запрос, который стал медленно был очень распространенным в нашем приложении:Периодически медленный стол Mysql - почему?

SELECT * FROM `posts` WHERE (`posts`.forum_id = 1) ORDER BY posts.created_at DESC LIMIT 1; 

У нас есть индекс по таблице сообщений на (forum_id, created_at), который обычно позволяет этот запрос и сортировка произойдет в памяти. Но, в течение этих трех часов, не только. Обычно это мгновенный запрос составлял от 2 секунд до 45 секунд в течение этого периода времени. Затем он вернулся к норме.

Я просмотрел наш медленный журнал запросов и ничего больше не выглядит обычным. Я смотрел New Relic (это приложение Rails), и все остальные действия выполнялись, по сути, с той же скоростью, что и в обычном режиме. Сегодня у нас не было необычного количества сообщений. Я не могу найти ничего лишнего в наших журналах. И база данных не менялась, когда у нее все еще были возможности использовать память.

Мне интересно, может ли Mysql передумать, какие индексы использовать для заданного запроса, и по какой-то причине он решил решить полное сканирование таблицы по этому запросу в течение нескольких часов сегодня? Но если бы это было так, почему бы он прекратил выполнять полное сканирование таблицы?

Неужели кто-нибудь еще сталкивался с периодически прерывистым запросом, который игнорировал разум? Или у вас есть какие-то творческие идеи о том, как можно было бы отлаживать такую ​​проблему?

ответ

2

Я бы попробовать MySQL EXPLAIN заявление ...

EXPLAIN SELECT * FROM `posts` WHERE (`posts`.forum_id = 1) ORDER BY posts.created_at DESC LIMIT 1; 

Это может быть стоит проверить время отклика MySQL в вашем коде Rails, и если он превышает порог затем запустить EXPLAIN и где-то регистрировать детали ,

Table locking также источник на ум - это таблица сообщений, обновляемая cronjob или массивным запросом, когда выполняются SELECT?

Надеюсь, что это поможет!

2

На сайте, над которым я работаю, мы недавно переключились на InnoDB из MyISAM и we found that some simple select queries which had both WHERE and ORDER BY clauses were using the index for the ORDER BY clause, что привело к сканированию таблицы, чтобы найти несколько желаемых строк (но, черт возьми, их не нужно сортировать, когда они наконец-то нашли их все!)

Как указано в связанной статье, если у вас небольшое значение LIMIT, предложение ORDER BY является первым членом первичного ключа (поэтому данные по файлу упорядочены им), и есть много результатов, которые соответствуют вашему предложению WHERE, используя этот индекс ORDER BY - неплохая идея для MySQL. Однако я предполагаю, что created_at не является первым членом вашего первичного ключа, поэтому в этом случае это не особенно умная идея.

Я не знаю, почему MySQL будет переключать индексы, если вы ничего не изменили, но я предлагаю вам попробовать запустить ANALYZE TABLE в соответствующей таблице. Вы также можете изменить запрос, чтобы удалить предложения LIMIT и ORDER BY и отсортировать их на уровне приложения, если набор результатов достаточно мал; или вы можете добавить a USE INDEX hint, чтобы он никогда не догадывался, что неправильно.

Вы также можете указать change the wait_timeout value to something smaller, чтобы эти запросы, которые используют плохой индекс, просто никогда не завершались (но также не отставали от всех законных запросов). Вы по-прежнему сможете запускать длинные запросы в интерактивном режиме, даже с небольшим wait_timeout, поскольку для этого есть отдельный параметр конфигурации.