2009-08-15 12 views
3

J'ai une requête dans MySQL (utilisée dans une procédure stockée) qui recherche par nom et un autre champ. Lorsque j'utilise différentes combinaisons de ces paramètres de recherche, j'obtiens des résultats rapides (entre 1 et 2) mais avec des valeurs particulières, j'obtiens une requête qui prend 9s pour retourner les résultats sur le site de production. Voici ce que je suis sorti de la EXPLAIN:Slow MySQL Query

id, select_type, table, type, possible_keys, key,  key_len, ref, rows, Extra 
-------------------------------------------- 
1, SIMPLE,  Names, ref, IX_Name,  IX_Name, 17,  const, 3173, Using where 

Nom est déclaré comme varchar (40) et l'autre champ est Unsigned smallint (6). J'utilise un index sur les 15 premiers caractères du nom (IX_Name) qui est utilisé dans la requête. Je peux voir que les requêtes lentes obtiennent un assez grand nombre de lignes à vérifier dans la colonne "rows" de la sortie EXPLAIN.

Je ne suis pas sûr de ce que je peux faire pour améliorer la performance. Y a-t-il quelque chose de sensiblement faux avec la sortie EXPLAIN ci-dessus?

Merci, Tim

+2

Cela peut être une bonne idée de publier la requête à exécution lente. – karim79

+1

Pourriez-vous afficher votre déclaration SQL? En outre, il peut être utile de connaître la cardinalité des noms stockés dans votre table. – DBMarcos99

Répondre

3

Comment avez-vous remplir la table? Les index sont des structures arborescentes et pour fonctionner efficacement, ils doivent être équilibrés - ce qui se fera automatiquement si la table est chargée par lots ou si une maintenance régulière est appliquée. Si aucun d'entre eux n'est vrai alors l'indice sera significativement moins efficace pour les parties de l'arbre qui ont grossi excessivement.

La vérification la plus simple consiste à supprimer l'index et à le recréer. Si vous avez le même comportement après, c'est autre chose, mais au moins c'est une possibilité éliminée.

+0

Salut Cruachan. Merci pour votre réponse. J'ai une table de 4 millions de lignes MYISAM et je la mets à jour toutes les semaines. Lorsque je fais une mise à jour (d'environ 2000 lignes chaque semaine), puis j'effectue les déclarations suivantes: modifier les noms de table ordonnée par namenumber desc; optimiser les noms de table; analyser les noms des tables; mais je ne modifie pas l'index ou le recréer ... pourrait-il être le problème que vous avez dit que l'index peut être déséquilibré? Parce que cela expliquerait pourquoi cela ne se produit qu'avec certains noms. Merci, Tim –

+0

Il vaudrait la peine de laisser tomber l'index et de le recréer pour l'essayer. Je n'ai jamais DBA'd une base de données MySQL grande donc je n'ai aucune expérience directe, mais c'était certainement le cas de plusieurs très grandes bases de données Oracle que j'ai l'habitude d'administrer. Généralement, les gens se concentrent sur la structure de la table et oublient que les index sont aussi des structures de stockage et devraient également être gérés. – Cruachan

+0

Si vous le faites j'apprécierais si vous avez posté le résultat. – Cruachan

1

Ok, vous avez un index sur un préfixe. Vous utilisez les 15 premiers caractères, mais nous allons vous faire semblant utilisé seulement 1, et votre table avait ces valeurs pour les noms:

Al Barb Beth Betsy Bill Biff Bob Bonny Buck Bud Carl

Étant donné que mon index ne porte que sur le premier caractère, la base de données doit lire toutes les lignes renvoyées par l'index et comparer chaque nom entier au prédicat. Maintenant, si je cherche 'Al', mon index retourne une ligne. Je compare ensuite 'Al' dans le prétexte à 'Al' dans la rangée, et j'ai une correspondance, donc je retourne cette rangée, et j'ai terminé. Maintenant, si je cherche 'Alex', mon index donne une ligne en arrière. Je compare alors 'Alex' dans le prétexte à 'Al' dans la rangée, et je n'ai aucun match, et plus de match potentiel, et j'ai terminé. Mais si je cherche 'Bud' (ou quelque chose commençant par 'B'), mon index donne neuf rangées. J'ai neuf lignes à lire et à comparer au prédicat, avant que j'aie fini.

Faites ceci:

select substring(name, 1, 15), count(*) 
from names 
group by substring(name, 1, 15); 

Je pense que vous trouverez vos recherches rapides ont sont uniques, tandis que les lentes sont où de nombreux noms partagent un préfixe commun.

+0

Merci pour votre réponse ... La chose est, je cherche le nom complet (Fischer) donc dans ce cas, je ne pense pas que le préfixe est un problème car il est inférieur à 15 caractères de toute façon ... Et je pense que le les noms sont presque uniques après 15 caractères. Merci, Tim –

0

Je trouve 3173 lignes pour considérer un assez grand nombre, en supposant que vous voulez les rendre à un utilisateur. Si le nombre réel d'enregistrements récupérés est sensiblement inférieur, vous devriez envisager de créer plus d'indices. Il serait utile de savoir ce que EXPLAIN rapporte pour un terme de recherche différent.

2

Il semble que votre requête utilise uniquement l'index pour un champ. Vous avez mentionné que vous faites une recherche par nom et "un autre champ". MySQL (à l'exception d'une version très récente dans des circonstances particulières) est limité à un index par occurrence de table dans une requête. Cela signifie que si vous avez un index sur le nom et l'index sur l'autre champ, MySQL devra probablement deviner quel index serait le plus utile et ignorer l'autre. Il semble qu'une meilleure structure de requête ou définition d'index serait utile. Si votre nom est assez unique et que vous obtenez 3 000 lignes dans le plan d'explication, alors les métadonnées dans la base de données ne sont pas bonnes ou vous avez une tonne d'autres possibilités dans l'autre champ.

Pouvez-vous publier la requête et le schéma de la table?

Vos requêtes sont-elles toujours rapides ou toujours lentes pour le même SQL? c'est-à-dire que si vous recherchez Fisher, c'est parfois rapide et parfois lent ou cohérent. Si elles sont cohérentes, cela est probablement dû à l'activité du processeur ou du disque. S'il est variable, il est probablement dû à d'autres requêtes sur la base de données. En outre, en fonction de ce que vous sélectionnez, si vous pouvez obtenir votre résultat complet dans un index, votre requête volera, car il n'aura pas à frapper le disque pour vérifier les enregistrements. J'ai eu des améliorations assez étonnantes avec les requêtes "using index".

Jacob