2009-12-22 5 views
1

J'ai une requête que j'ai faite dans une vue MYSQL. Cette vue particulière est au cœur de notre application, nous cherchons donc à la régler. Il y a une clé primaire sur Map_Id, User_No, X, Y. Je suis assez à l'aise de régler les requêtes du serveur SQL, mais je ne suis pas vraiment sûr de la façon dont MySql fonctionne dans cet aspect. Serait-il utile de mettre un index sur les points et update_stamp? Les lectures sur cette table sont de 90%, donc bien qu'il y ait beaucoup d'insertions, cela ne se compare pas à la quantité de lectures. Description: Obtenir la personne ayant le plus de points pour chaque coordonnée x, y dans une carte donnée. Cravate rupture par qui a le dernier timbre de mise à jour, puis par ID utilisateur.Optimisation de la requête mysql

SELECT GP.Map_Id AS Map_Id,GP.User_No AS User_No,GP.X AS X,GP.Y AS Y, GP.Points AS Points,GP.Update_Stamp AS Update_Stamp 
    FROM (Grid_Points GP LEFT JOIN Grid_Points GP2 
     ON (
     (
     (GP2.Map_Id = GP.Map_Id) AND (GP2.X = GP.X) AND (GP2.Y = GP.Y) AND 
     ((GP2.Points > GP.Points) OR ((GP2.Points = GP.Points) AND (GP2.Update_Stamp > GP.Update_Stamp)) OR 
     ((GP2.Points = GP.Points) AND (GP2.Update_Stamp = GP.Update_Stamp) AND (GP2.User_No < GP.User_No))) 
     ) 
) 
) 

WHERE ISNULL(GP2.User_No); 

Répondre

3

Wow man, vous aimez vraiment utiliser des parenthèses. :-)

Vous avez raison, un index composé peut aider. Vous pourriez même être en mesure d'en faire un indice de couverture. Probablement soit un index sur Grid_Points(Map_Id,X,Y) ou bien un index sur Grid_Points(Points,Update_Stamp,User_No) serait ce que j'essaye.

Toujours tester l'optimisation des requêtes avec EXPLAIN pour voir si l'optimiseur utilise votre index. Lisez cette section de documentation jusqu'à ce que vous compreniez les notes cryptiques dans le rapport EXPLAIN.

Le rapport EXPLAIN va probablement vous montrer l'index qu'il décide d'utiliser. Vous devez savoir que MySQL utilise un seul index par table dans une requête donnée.

Voilà comment je voulais écrire cette requête, en se fondant sur l'ordre de préséance entre AND et OR au lieu de tant de parenthèses imbriquées:

SELECT GP.Map_Id, GP.User_No, GP.X, GP.Y, GP.Points, GP.Update_Stamp 
FROM Grid_Points GP LEFT JOIN Grid_Points GP2 
    ON GP2.Map_Id = GP.Map_Id AND GP2.X = GP.X AND GP2.Y = GP.Y 
    AND (
     GP2.Points > GP.Points 
     OR 
     GP2.Points = GP.Points 
     AND GP2.Update_Stamp > GP.Update_Stamp 
     OR 
     GP2.Points = GP.Points 
     AND GP2.Update_Stamp = GP.Update_Stamp 
     AND GP2.User_No < GP.User_No 
    ) 
WHERE GP2.User_No IS NULL; 

Vous utilisez ma méthode préférée pour trouver le plus grand-n-par groupe en MySQL. MySQL n'optimise pas très bien le GROUP BY (il s'agit souvent d'une table temporaire qui est sérialisée sur le disque), donc la solution de jointure externe gauche que vous utilisez est généralement bien meilleure, du moins pour MySQL. Dans d'autres marques de SGBDR, cette solution peut ne pas avoir un tel avantage.

+0

En fait, je déteste toutes les parenthèses, mais j'ai dû exporter la vue pour voir la structure et elle les avait mises dedans. J'ai fait une explication et j'ai vu qu'elle faisait un scan complet. Je vais essayer un indice de couverture. Merci beaucoup!! – Codezy

+0

Merci pour l'info. BTW J'ai testé ma solution sur certains échantillons de données, et c'est à peu près la même vitesse, je ne savais pas sur l'autre façon de le faire. La vraie solution que vous mentionnez est dans l'index, Map_Id, X, Y aide beaucoup plus que Points, Update_Stamp, User_No Vous expliquer comment cette requête fonctionne/où je peux lire sur ce style? – MindStalker

+0

Suivez la balise 'most-n-per-group' ici à StackOverflow. Il existe des dizaines de problèmes similaires avec des solutions. –

1

Je ne correspondraient pas à lui-même, je le ferais en tant que « groupe par », puis de nouveau correspondre éventuellement pour obtenir la personne qui est.

SELECT Map_Id, X, Y, max (points) FROM Grid_Points GROUP BY ID_de_module, X, Y; Cela vous donnera une table de Map_Id, X, et Y, puis le maximum de points. Vous pouvez ensuite joindre ces résultats à Grid_Points pour trouver l'utilisateur = à ces points.

+0

vous avait aussi à indexer (pas un index unique juste un index) map_id, X, Y, Points – MindStalker

+0

Nous avons commencé avec le maximum et le groupe par et changé notre méthode actuelle. Je vais essayer les deux pour voir la différence de performance. – Codezy