RE: Système de quêtes et comment les vérifier ? - Xenos - 22-03-2014
Tu peux toujours changer un
SELECT ... FROM `listeObjets` LEFT JOIN `typeObjet` on `typeObjet`.`id`=`listeObjet`.`idType`
en
SELECT `x`, `y`,
CASE `idType`
WHEN 0 THEN "losange"
WHEN 1 THEN "pentagone-pointe-vers-bas"
WHEN 2 THEN "pentagone-pointe-vers-haut"
WHEN 3 THEN "losange-bouclage-X"
END AS `type` FROM `cases`
généré via
'SELECT `x`, `y`, CASE `idType`'
.implode(
'',
array_map(
function ($p_idType, $p_description)
{
return ' WHEN '.$p_idType.' THEN "'.$p_description.'"';
}
,array_keys($consts->typesCase) // Liste des id des types de quêtes
,array_values($consts->typesCase) // Liste des valeurs associées à chaque type de quête
)
)
.' END AS `type` FROM `cases`';
Où $consts est l'objet contenant les constantes avec les types de quêtes (ou ici, de cases).
La jointure est donc remplacée par un switch.
Au niveau de la requête elle-même, ce n'est pas très beau, mais cela allège le coté BDD (évite l'ajout d'une table).
En revanche, niveau perf', c'est tout dans un mouchoir de poche:- Requête simple (SELECT ... `idTypeQuete`): 3s (100%)
- Requête avec jointure (SELECT ... `listeTypes`.`nom` FROM ... LEFT JOIN `listeTypes` ON `listeTypes`.`id`=`quetes`.`idTypeQuete`): 3.5s (~117%)
- Requête switch (avec CASE...WHEN...THEN...END): 3.4s (115%)
Je ne peux pas faire de test pertinent avec la requête simple + la classe avec les constantes, car il faudrait "déplier" la liste des résultats pour appliquer la valeur issue de la classe des constantes.
Donc, niveau perf', il semblerait que les méthodes se valent ("select" simple, jointure, switch dans la requête ou utilisation d'une classe avec des constantes lorsque l'on parcours les résultats de la requête).
PS: Je n'ai pas testé l'énumération (type ENUM dans MySQL) car il ne permet pas d'assurer que les mêmes types de quêtes se retrouveront d'une table à l'autre, si l'id du type de quête est utilisé dans plusieurs tables. S'il n'y a qu'une table de quêtes, autrement dit si la table "listeTypesQuetes" sur laquelle la jointure serait faite n'est pas utilisée par une autre table, alors j'envisagerai un ENUM, adapté à ce genre de cas.
Après quelques tests, je peux quand même dire que:- La méthode "class avec des quasi-constantes" (aka attributs ou constantes qui contiennent les données comme le nom du type de quête) est plus rapide qu'une jointure, à condition de parcourir la liste des résultats retournés (foreach).
Le ratio est de 6s pour la jointure, contre 3.5 pour le select, suivit dans le foreach de la récupération des données issues de la classe avec les quasi-constantes.
- Plus la classe avec les quasi-constantes contient de nombreuses données, plus l'écart se creuse. Ainsi, si la table des types de quête contient, disons, 5 colonnes (id + 4 colonnes de données), le rapport est plutôt de 7s contre 3.5s
L'utilisation d'une classe avec des constantes/attributs est donc intéressante si les quêtes changent peu, et que l'on a beaucoup de données associées à chaque type de quête.
Code utilisé:
Code PHP : <?php
$mysqli = new mysqli('127.0.0.1', 'root', '', 'eclerd_earth');
// classe avec les données quasi-constantes
// J'utilise un attribut public par facilité
// une constante de classe n'est pas toujours envisageable, car elles ne peuvent pas contenir de tableau par exemple
class consts
{
public $typesCase = array(
0 => array('losange', 0, 0, 'KAWAI DESU DESU DESU DESU DESU DESUNE?!'),
1 => array('pentagone-pointe-vers-bas', 0, 0, 'KAWAI DESU DESU DESU DESU DESU DESUNE?!'),
2 => array('pentagone-pointe-vers-haut', 0, 0, 'KAWAI DESU DESU DESU DESU DESU DESUNE?!'),
3 => array('losange-bouclage-X', 0, 0, 'KAWAI DESU DESU DESU DESU DESU DESUNE?!')
);
}
$ticker = new \Globals\Debug\Ticker(); // Chronomètre
$consts = new consts();
$req = 'SELECT `x`, `y`, `idType` FROM `cases`'; // Sélection des données dans la table de 550k lignes
$cases = $mysqli->query($req);
foreach ($cases as $case)
{
$data = $consts->typesCase[$case['idType']]; // Récupération des données sous la forme d'un tableau
}
$ticker->nextTick('Query simple');
// Fin de chronomètre; celui-ci est réinitialisé pour la suite du code
$req = 'SELECT `cases`.`x`, `cases`.`y`, `typesCase`.`foo`, `typesCase`.`taille`, `typesCase`.`hauteur`, `typesCase`.`description`'
// Récupération des mêmes données
.' FROM `cases` JOIN `typesCase` ON `typesCase`.`idType`=`cases`.`idType`';
// Jointure
$cases = $mysqli->query($req);
foreach ($cases as $case)
{
$type = array($case['foo'], $case['taille'], $case['hauteur'], $case['description']);
// Construction d'un tableau identique au précédent
}
$ticker->nextTick('Query jointure'); // Fin de chronomètre
var_dump($ticker->getSortedDurations()); // Durées: 7s pour la jointure, 3.5s pour la class
?>
RE: Système de quêtes et comment les vérifier ? - Argorate - 23-03-2014
Sinon y a la solution optimal: tu mets en bd pour pouvoir gérer via une interface et faire les jointures mais, via un script, tu gèneres le fichier php avec les constantes/variable de classe (et les rares MAJ des type de quest, tu régénères via ce même script), du coup quand tu as besoin d’accès direct, genre le nom d'une quete via l'id, tu as pas de sql à faire.
RE: Système de quêtes et comment les vérifier ? - php_addict - 23-03-2014
Merci pour tout vos conseils judicieux, je suis en plein développement des quêtes, ca va etre cool !!!
|