[Mysql] Selection max

Selection max [Mysql] - SQL/NoSQL - Programmation

Marsh Posté le 27-03-2008 à 11:52:54    

Bonjour,
 
Mon titre n'est pas très explicite, mais j'aurais besoin de vos conseil.
 
Voici mon problème.
 
J'ai une table unique qui contient une colonne ID en auto incrément, une colonne Id produit,une colonne Id du client, une colonne action,une colonne utilisateur et une colonne date d'action.

Code :
  1. ---------------------------------------------------------------------
  2. | ID  | ID_PRODUCT | CLIENT_ID | ACTION_TYPE | USER |  ACTION_DATE  |
  3. ---------------------------------------------------------------------


 
Dans cette table, a chaque fois qu'un utilisateur effectue une action j'en garde une trace.
 
Je souhaiterais (en une requête si possible) récupérer la dernière action effectuée sur chaque produit
 
J'ai essayé une requête du type :  
 

Code :
  1. SELECT * FROM TBLORDERS T WHERE ACTION_DATE=(SELECT MAX(ACTION_DATE) FROM TBLORDERS T1 WHERE T.ID_PRODUCT=T1.ID_PRODUCT)


 
Le problème c'est que cela met vraiment trop de temps (mais alors vraiment : 15 minutes min)
 
Auriez-vous une idée?
 
Merci d'avance

Reply

Marsh Posté le 27-03-2008 à 11:52:54   

Reply

Marsh Posté le 27-03-2008 à 13:10:58    

La requête a l'air d'être bien celle qu'il faut (j'en ai déjà fait plusieurs du même genre). Pour optimiser, il suffit de rajouter un index secondaire sur ID_PRODUCT.

Reply

Marsh Posté le 27-03-2008 à 14:39:56    

Arf , j'ai déjà un index secondaire et en plus je ne teste que sur une base contenant que 200.000 lignes alors qu'en production, j'en aurais au minimum 1.000.000.
 
En tout cas merfci pour la confirmation de ma requête.
 
Si quelqu'un a une autre sugestion je suis preneur :)

Reply

Marsh Posté le 28-03-2008 à 02:22:32    

essaie de créer un index qui porte à la fois sur id_product et action_date
 
en effet, si t'as beaucoup d'actions pour un même produit, tu vas avoir de sérieux problèmes pour évaluer le max(), et ensuite pour retrouver la ligne qui correspond à ce que t'as trouvé.
avec un index, tu devrais même plus avoir le temps de voir que t'as tapé sur [Enter] ;)
 
tu peux aussi éventuellement passer par une auto-jointure et une clause HAVING... Ca peut éventuellement être plus rapide.
 
Avec une table toute pourrie pas bien indexée, la seconde solution prends 32% du lot SQL alors que la première prend 68% du lot avec SQL Server 2005 Express.
 

Code :
  1. SELECT *
  2. FROM mention m1
  3. WHERE m1.note = (SELECT max(m2.note) FROM mention m2 WHERE m2.libelle = m1.libelle)
  4.  
  5. SELECT max(m1.note), m2.note, m2.libelle
  6. FROM mention m1
  7. INNER JOIN mention m2 ON m2.libelle = m1.libelle
  8. GROUP BY m2.note, m2.libelle
  9. HAVING max(m1.note) = m2.note


 
Une fois l'index proposé, je passe de 200ms à 1ms pour les deux requêtes, et la proportion s'inverse : 49% pour la première, et 51% pour la seconde.
 
C'est donc à tester sur ton SGBD, tes index et ta volumétrie, y'a pas de conclusion universelle à tirer -mise à part que l'index améliore considérablement les performances ;)-
=> Pour la première requête, en fait le plan d'exécution se simplifié énormément, tandis que pour la seconde, il se bordelise un max ;)
 
L'index préconisé :

Code :
  1. CREATE INDEX m_idx ON mention (libelle, note)


 
Avant index :
http://img257.imageshack.us/img257/9466/avantgi3.png
 
Après index :
http://img527.imageshack.us/img527/9087/aprsfe8.png


Message édité par MagicBuzz le 28-03-2008 à 02:39:29
Reply

Marsh Posté le 28-03-2008 à 12:11:13    

Un grand merci pour les explications, je vais tester et je vous fait un feed.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed