7
votes

MySQL lent sur Join. N'importe quel moyen d'accélérer

J'ai 2 tables. 1 est la musique et 2 est Listentrack. Listentrack suit les jeux uniques de chaque chanson. J'essaie d'obtenir des résultats pour des chansons populaires du mois. Je reçois mes résultats mais ils prennent juste trop de temps. Ci-dessous mes tables et mes requêtes

430 000 lignes xxx

12500 lignes xxx

Cette requête n'est pas très complexe Et les rangées ne sont pas trop grandes, je ne pense pas.

Y a-t-il un moyen de vous accélérer? Ou pouvez-vous suggérer une meilleure solution? Cela va être un travail cron au début de chaque mois, mais j'aimerais également faire par les résultats de la journée.

OH BTW Je l'exécute localement, plus de 4 minutes à courir, mais sur pousser, il faut environ 45 secondes


0 commentaires

9 Réponses :


4
votes

Essayez de créer un index qui aidera à la jointure: xxx


0 commentaires

12
votes

Je suis plus d'un gars SQL Server, mais ces concepts doivent s'appliquer.

J'ajouterais des index:

  1. sur Listentrack, ajoutez un index avec URL et date_créated
  2. sur la musique, ajoutez un index avec URL

    Ces index devraient accélérer énormément la requête (j'avais à l'origine les noms de table mélangés - fixés dans la dernière modification).


4 commentaires

Je crois que les noms de table d'index sont retournés. J'ai réussi à faire cela la première fois aussi et je l'ai attrapé juste avant de poster.


Thejacobtaylor avait raison, j'ai eu les noms de table à l'envers. J'ai réparé cela.


La question que j'ai, c'est pourquoi avons-nous les deux les avoir recouties? J'ai parcouru à travers le poteau, mais je n'ai pas vu le déclencheur que je me suis trompé.


Mon hypothèse est la suivante: dans l'introduction de la question, ils sont introduits en tant que musique puis listentrack, mais les requêtes de création montrent à Listentrack en premier.



6
votes

Pour la plupart, vous devez également indexer toute colonne utilisée dans une jointure. Dans votre cas, vous devez indexer les deux listentrack.url et music.url

@jeff s - un index music.Date_Created ne serait pas aidée parce que vous allez à travers un Fonction d'abord, MySQL ne peut pas utiliser un index sur cette colonne. Souvent, vous pouvez réécrire une requête de sorte que la colonne référencée indexée soit utilisée statiquement comme: xxx

devient xxx

ceci Filtrera la baisse des enregistrements de 2009-08-15 et permettra à tous les indices sur cette colonne d'être candidats. Notez que MySQL pourrait ne pas utiliser cet index, cela dépend d'autres facteurs.

Votre meilleur pari est de créer un double index sur listentrack (URL, date_created) puis un autre index sur musique.url

ces 2 index couvrira cette requête particulière.

Notez que si vous exécutez Expliquer Sur cette requête, vous allez toujours obtenir un à l'aide de FilesTort car il doit écrire les enregistrements à une table temporaire sur le disque pour effectuer la commande par.

En général, vous devez toujours exécuter votre requête sous Expliquer pour avoir une idée sur la manière dont MySQL exécutera la requête puis passer de là. Voir le Expliquer Documentation:

http://dev.mysql.com/doc/refman/5.0/fr/Und-Explain.html


2 commentaires

Chronométrage brutal. :) Excellente réponse. Battez-moi en quelques secondes.


Merci beaucoup semble très utile. Je vais suivre votre lien et lire et essayer votre exemple



3
votes

Je pense que j'ai peut-être manqué l'évidence avant. Pourquoi rejoignez-vous la table de musique du tout? Vous ne semblez pas utiliser les données de cette table et vous effectuez une jointure gauche qui n'est pas requise, non? Je pense que cette table étant dans la requête rendra beaucoup plus lente et n'ajoutera aucune valeur. Prenez toutes les références à la musique, à moins que l'inclusion de l'URL n'est requise, auquel cas vous avez besoin d'une jointure droite pour le forcer à ne pas inclure une ligne sans valeur correspondante.


J'ajouterais de nouveaux index, comme les autres mentionnent. Spécifiquement j'ajouterais: URL de la musique LISTENTRACK DATARE_CREATED, URL

Cela améliorera votre jointure une tonne.

Ensuite, je regarderais la requête, vous forcez le système pour effectuer des travaux sur chaque rangée de la table. Il serait préférable de reformuler la restriction de date comme une plage.

Pas sûr de la syntaxe de la tête de la tête: Où '2009-08-15 00:00:00' <= Date_Créré <2009-08-16 00:00:00

Cela devrait permettre d'utiliser rapidement l'index pour localiser les enregistrements appropriés. L'indice combiné à deux clés sur la musique devrait permettre de trouver les enregistrements basés sur la date et l'URL. Vous devriez expérimenter, ils pourraient mieux aller d'aller dans l'URL d'une autre direction, Date_Créré sur l'index.

Le plan d'explication de cette requête doit dire "à l'aide d'index" sur la colonne de droite pour les deux. Cela signifie qu'il n'aura pas besoin de toucher les données dans le tableau pour calculer vos sommes.

Je vérifierais également les paramètres de mémoire que vous avez configurés pour MySQL. On dirait que vous n'avez pas assez de mémoire alloué. Soyez très prudent sur les différences entre les paramètres de serveur et les paramètres basés sur le thread. Le serveur avec un cache de 10 Mo est assez petit, un thread avec un cache de 10 Mo peut utiliser rapidement beaucoup de mémoire.

jacob


2 commentaires

J'utilise des données dans cette table, mais je déboguais là où vient la lenteur. Pas de jointure 1 sec requête. Inscrivez-vous après l'ajout de l'index IDX sur la musique.url a couru à 7 secondes et ajout de musique.Plays la poussé jusqu'à 10


Pouvez-vous poster le plan d'explication pour la "vraie" requête ou celle avec l'index? Combien d'enregistrements parlons-nous pendant une journée (ordre de grandeur)? Combien de mémoire utilisez-vous sur la boîte? Index et cachets de données, ou juste cache sur InnoDB, sont essentiels et faciles à réparer.



0
votes

Après que vous ajoutez des index, vous voudrez peut-être explorer l'ajout d'une nouvelle colonne pour que la date_créated soit un UNIX_TMESTAMP, qui fera des opérations de mathématiques plus rapides.

Je ne suis pas certain pourquoi vous avez la fonction DIFF, comme il apparaît, vous recherchez toutes les lignes mises à jour à une date donnée.

Vous voudrez peut-être regarder votre requête car il semble avoir une erreur.

Si vous utilisez des tests d'unité, vous pouvez comparer les résultats de votre requête et une requête à l'aide d'un horodatage UNIX à la place.


0 commentaires

1
votes

Pourquoi répétez-vous l'URL dans les deux tables?

Demandez à la liste de Listentrack. Se débarrasse de la recherche de texte ainsi que de l'index supplémentaire.

En plus, il est sans doute plus correct. Vous suivez les temps où une piste particulière a été écoutée, pas l'URL. Et si l'URL change?


0 commentaires

0
votes

Vous voudrez peut-être ajouter un index au champ URL des deux tables.

Cela dit, lorsque je suis converti de MySQL en SQL Server 2008, avec les mêmes requêtes et les mêmes structures de base de données, les requêtes ont couru 1 à 3 ordres de grandeur plus rapidement.

Je pense que certains d'entre eux ont eu à voir avec les SGBDM (optimiseurs MySQL ne sont pas si bons ...) et certains d'entre elles auraient pu faire avec la manière dont les ressources du système de réserve de RDBMS. Bien que les comparaisons ont été effectuées sur des systèmes de production où seul le DB fonctionnerait.


0 commentaires

3
votes

Pré-regroupement puis rejoindre rend les choses beaucoup plus rapidement avec MySQL / Myisam. (Je suis suspect moins de ceci est nécessaire avec d'autres dB)

Ceci devrait fonctionner aussi vite que la version non jointe: xxx p.s. - La mappage entre les deux tables avec un identifiant au lieu d'une URL est un avis sonore.


0 commentaires

0
votes

Ceci ci-dessous fonctionnerait probablement pour accélérer la requête.

Créer index music_url_index sur la musique (URL) à l'aide de BTREE; Créer Index Listentrack_url_Index sur Listentrack (URL) à l'aide de BTREE;

Vous devez vraiment connaître le nombre total de comparaisons et de balayages de ligne qui se produisent. Pour obtenir cette réponse, regardez le code ici de la façon de faire cela en utilisant Expliquer http: / /www.siteconsortium.com/h/p1.php?id=MYSQL002 .


0 commentaires