2009-08-10 13 views
3

Nous avons récemment eu un problème que je n'avais jamais vu auparavant, où, pendant environ 3 heures, l'une de nos tables Mysql est devenue extrêmement lente. Cette table contient les messages du forum et contient actuellement environ un million de lignes. La requête qui est devenu lent était très commun dans notre application:Table Mysql lentement intermittente - pourquoi?

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

Nous avons un index sur la table messages sur (forum_id, created_at) qui permet normalement cette requête et trier pour arriver en mémoire. Mais, pendant ces trois heures, notsomuch. Ce qui est normalement une requête instantanée va de 2 secondes à 45 secondes pendant cette période. Ensuite, il est revenu à la normale.

J'ai parcouru notre journal de requête lente et rien d'autre ne sort de l'ordinaire. J'ai regardé New Relic (il s'agit d'une application Rails) et toutes les autres actions ont fonctionné essentiellement à la même vitesse que la normale. Nous n'avions pas un nombre inhabituel de messages de messages aujourd'hui. Je ne trouve rien d'autre d'étrange dans nos journaux. Et la base de données n'échangeait pas, quand il avait encore des concerts de mémoire à utiliser. Je me demande si Mysql pourrait changer d'avis sur les index à utiliser pour une requête donnée, et pour une raison quelconque, il a commencé à décider de faire une analyse de table complète sur cette requête pendant quelques heures aujourd'hui? Mais si cela était vrai, pourquoi aurait-il cessé de faire les analyses de table complètes?

Est-ce que quelqu'un d'autre a rencontré une requête par intermittence lente qui a défié la raison? Ou avez-vous des idées créatives sur la façon dont on pourrait déboguer un problème comme celui-ci?

Répondre

2

Je vais essayer la déclaration MySQL EXPLAIN ...

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

Il peut être utile de vérifier le temps de réponse MySQL dans votre code Rails, et si elle dépasse un certain seuil puis exécutez le EXPLAIN et connectez-vous quelque part les détails .

Table locking vient également à l'esprit - la table posts est-elle mise à jour par une requête cronjob ou hefty pendant que SELECTs se déroule?

Espérons que ça aide un peu!

2

Sur un site sur lequel je travaille, nous avons récemment basculé vers InnoDB à partir de MyISAM, et we found that some simple select queries which had both WHERE and ORDER BY clauses were using the index for the ORDER BY clause, résultant en une analyse de table pour trouver les quelques lignes désirées (mais, diable, ils n'ont pas besoin d'être triés quand ils ont finalement trouvé Comme indiqué dans l'article lié, si vous avez une petite valeur LIMIT, votre clause ORDER BY est le premier membre de la clé primaire (donc les données du fichier sont ordonnées par elle), et il y a beaucoup de résultats qui correspondent à votre clause WHERE, en utilisant cet index ORDER BY n'est pas une mauvaise idée pour MySQL. Cependant, je suppose que created_at n'est pas le premier membre de votre clé primaire, donc ce n'est pas une idée particulièrement intelligente dans ce cas. Je ne sais pas pourquoi MySQL changerait d'index si vous n'avez rien changé, mais je vous suggère d'essayer ANALYZE TABLE sur le tableau correspondant. Vous pouvez également modifier la requête pour supprimer les clauses LIMIT et ORDER BY et les trier au niveau de l'application, à condition que le jeu de résultats soit assez petit; ou vous pouvez ajouter a USE INDEX hint afin qu'il ne devine jamais faux.

Vous pouvez aussi change the wait_timeout value to something smaller de sorte que ces requêtes qui utilisent un mauvais index ne se terminent simplement jamais (mais ne retardent pas non plus toutes les requêtes légitimes). Vous pourrez toujours exécuter de longues requêtes de manière interactive, même avec un petit wait_timeout, car il existe un paramètre de configuration distinct pour cela.