(15-06-2011, 11:01 AM)Zack a écrit : Normalement, une procédure stockée est dans tous les cas plus rapide puisqu'elle est pré-compilé sur le serveur. Donc on transfert beaucoup moins d'informations du client au serveur et le serveur travaille moins du coup puisqu'il n'a pas besoin de la réinterpréter à chaque fois.
Ça c'est pas tout à fait vrai..
La procédure est pré-compilée, mais pas son résultat... Une requête SQL sera pré-compilée aussi avant d'être exécuter, tu ne gagnes donc que le temps de "pré-compilation" du code de la requête, autrement dit, sur une requête de quelques lignes : rien du tout.
La "pré-compilation" d'une procédure stockée dans MySQL n'est d'ailleurs pas du tout présenté comme un avantage, mais comme une contrainte... en effet, le fait que la procédure soit pré-compilé fait que tu ne peux pas avoir de code "variable" dans ta procédure, c'est un dire par exemple exécuter une requête qui soit construite sous la forme d'une concaténation.
(15-06-2011, 11:01 AM)Zack a écrit : Après je ne sais pas combien de millisecondes ça fait gagner par rapport aux autres méthodes et ce serait assez galère de faire les benchmarks, mais depuis que je l'ai mise la charge du serveur a été divisé par 1.5. Donc dans mon cas, c'est bien utile ^^.
Je ne sais pas d'pù vient ton gain de performance, mais cela ne vient pas du faite que la procédure soit "pré-compilée".
(15-06-2011, 11:01 AM)Zack a écrit : Et sinon voici la vrai requête que j'utilise, celle que je donnais c'était juste pour faciliter la vue de mon problème :
SELECT UNIX_TIMESTAMP() as timestamp_, action_, action_lien, sortRecu, typeSortRecu, sortRecuPar, P.idJoueur, pseudo, x, y,
pvActuel, pvMax, reiatsuActuel, reiatsuMax, niveau, xp, koro, reputation, rang, clan, sexe, shinigami,
humain, transformation, combatEnCours, demandeCombat, etatPersonnage, boostPersonnage, avatarMJ
FROM personnage P
JOIN joueur J
JOIN caracteristique C
on J.idJoueur = P.idJoueur and C.idJoueur = P.idJoueur
WHERE x BETWEEN $minX and $maxX and y BETWEEN $minY and $maxY AND UNIX_TIMESTAMP(derniereActualisation) > (UNIX_TIMESTAMP()-600) AND P.idCarte = 0
Un peu plus compliqué que l'autre, et l'appeler toutes les 2 secondes méritait quand même que je la mette en procédure stockée.
Ensuite est ce que remplacer le BETWEEN par les opérateurs directement est plus rapide ?
Pour optimiser ta requête :
- utiliser des conditions dans te jointures "JOIN ma_table ON condition" ou "JOIN ma_table USING (index)"
- tous les champs dans les conditions doivent être indexé et avoir le même format (comparer un INT avec un INT et non un CHAR(1) par exemple) sinon, MySQL n'utilise tout simplement pas ses tables d'index
- utiliser ces jointures de préférances avec des ET et des =... les OU et autres ne passent pas par les index
Pour schématiser, dans MySQL tous les champs indexés se retrouvent dans un fichier/table à part... lorsque MySQL doit faire une recherche sur les index, il n'a qu'à pointer les lignes avec des index équivalent, ça ne représente donc presque aucun calcul. Si tu mets des OU ou pire des BETWEEN, MySQL est obligé de faire un calcul pour chaque champs, le temps de traitements augmente d'autant.
Ensuite, dans l'ordre MySQL va traiter les éléments de la requête grosso-modo dans l'ordre suivante :
- sélection des lignes dans les jointures de la première à la dernier jointure
- appliquer le WHERE sur le résultat obtenu
- appliquer les GROUP BY et autre HAVING
- appliquer les instructions du SELECT
Pour gagner du temps, il faut que les jointures soient restrictives, c'est à dire qu'elle réduisent le nombre d'enregistrement à traiter par le WHERE et non faire un produit cartésien : dans l'idéal la première table doit contenir le plus grand nombre d'enregistrement, la seconde doit réduire ce nombre de ligne en appliquant la condition de jointure, etc...
Autre remarque, les alias de table, si c'est pour rendre le code illisible, ça ne sert à rien, les alias ne sont vraiment utile que si tu dois avoir plusieurs fois la même table mais pour des jointures différentes...
Je reprend ton exemple :
SELECT UNIX_TIMESTAMP() as timestamp_, action_, action_lien, sortRecu, typeSortRecu, sortRecuPar, P.idJoueur, pseudo, x, y,
pvActuel, pvMax, reiatsuActuel, reiatsuMax, niveau, xp, koro, reputation, rang, clan, sexe, shinigami,
humain, transformation, combatEnCours, demandeCombat, etatPersonnage, boostPersonnage, avatarMJ
FROM personnage
JOIN joueur USING (idJoueur)
JOIN caracteristique USING (idJoueur)
WHERE x BETWEEN $minX and $maxX and y BETWEEN $minY and $maxY AND UNIX_TIMESTAMP(derniereActualisation) > (UNIX_TIMESTAMP()-600) AND P.idCarte = 0
Voilà pour les jointures...
La table "caracteristique" concerne le joueur ou le personnage ?
Si tu veux un peu plus d'aide, il me faut la structure de tes tables et un jeu de données de test