JeuWeb - Crée ton jeu par navigateur
Tests de performances de requêtes SQL - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Tests de performances de requêtes SQL (/showthread.php?tid=5338)

Pages : 1 2 3 4


Tests de performances de requêtes SQL - Argorate - 31-03-2011

Bonjour,

Je voudrais vous faire partager un constat des plus étrange, sans vouloir créer de polémique, j'aurais aimé qu'on puise discuter de ces observations.

En effet j'ai tester et comparer 4 moyens différents d'exécuter des requêtes SQL afin de savoir laquelle seraient la meilleure méthode d'un point de vue performance.

Les différentes methodes
Pour parler concrètement, j'ai tester les quatre méthodes suivante:


//DONNEES & INITIALISATION
$liste_methode = array('mysql', 'mysql_preparer', 'pdo', 'pdo_preparer');
$NB_BOUCLE = 100000;
$compteur=array(0,0,0,0);
$j=0;

//POUR CHAQUE METHODE
foreach($liste_methode as $id_methode => $methode)
{
$data = connect($id_methode); //CONNEXION BDD + PREPARATION REQUETE (le cas échéant)
$compteur[$j] += $data[1]; //ON AJOUTE LE TEMPS QUE COUT LA PREPARATION DE LA REQUETE (le cas échéant)

$i=0; $fonc='methode_'.$methode;
while($i < $NB_BOUCLE)
{
$compteur[$j] += $fonc($data[0]); //ON PASSE L'OBJET PDO (le cas échéant)
$i++;
}

//AFFICHAGE RESULTAT
echo 'Methode '.$methode.': '.(($compteur[$j]/$NB_BOUCLE)*1000).' ms, soit : '.($compteur[$j]/$NB_BOUCLE).' secondes (ou encore '.($compteur[$j]/60).' min) ['.$compteur[$j].' secondes pour '.$NB_BOUCLE.']<br />';

$j++;
}

function methode_mysql()
{
$time1 = microtime(true);
mysql_query('INSERT INTO test(nom) VALUES(\'test\')')
$time2 = microtime(true);
return ($time2 - $time1);
}

function methode_mysql_preparer()
{
$time1 = microtime(true);
mysql_query('EXECUTE test')
$time2 = microtime(true);
return ($time2 - $time1);
}

function methode_pdo($statement)
{
$time1 = microtime(true);
$statement->query('INSERT INTO test(nom) VALUES(\'test\')');
$time2 = microtime(true);
return ($time2 - $time1);
}

function methode_pdo_preparer($statement)
{
$time1 = microtime(true);
$statement->execute();
$time2 = microtime(true);
return ($time2 - $time1);
}

Avec pour les méthodes de requêtes préparer, ceci en plus : (executer juste après la connexion à la bdd)
(exécuter qu'une seule fois avant le début de la boucle, voilà pourquoi elle ne sont pas dans les fonctions ci-dessus)


//Pour mysql_preparé
$time1 = microtime(true);
mysql_query('PREPARE test FROM \'INSERT INTO test (nom) VALUES("test")\';');
$time2 = microtime(true);

//pour pdo_preparé
$time1 = microtime(true);
$statement = $connexion->prepare('INSERT INTO test(nom) VALUES(\'test\')');
$time2 = microtime(true);

J'ai effectuer les tests sur plusieurs série de requête:

En Lecture : SELECT de tous (sans WHERE)
En Lecture : SELECT d'un élément (avec WHERE sur un id)
En Écriture : INSERT

Et ce sur une table MyISAM, puis InnoDB. Les test sur 100 000 boucles sur des select étant trop long, j'ai majoritairement du me contenter de 10 000, mais je pense que c'est amplement suffisant pour voir apparaitre l'ordre de grandeur.


Résultats :

Code :
MyISAM
    10 000 enregistrements
        WHERE id=26
            Methode mysql : 0.22160313129425 ms, soit : 0.00022160313129425 secondes (ou encore 0.036933855215708 min) [2.2160313129425 secondes pour 10000]
            Methode mysql_preparer : 0.20994985103607 ms, soit : 0.00020994985103607 secondes (ou encore 0.034991641839345 min) [2.0994985103607 secondes pour 10000]
            Methode pdo : 0.22898020744324 ms, soit : 0.00022898020744324 secondes (ou encore 0.038163367907206 min) [2.2898020744324 secondes pour 10000]
            Methode pdo_preparer : 0.22423431873322 ms, soit : 0.00022423431873322 secondes (ou encore 0.037372386455536 min) [2.2423431873322 secondes pour 10000]
        
            AVEC PREPARE A CHAQUE ITERATION
            Methode mysql : 0.22766485214233 ms, soit : 0.00022766485214233 secondes (ou encore 0.037944142023722 min) [2.2766485214233 secondes pour 10000]
            Methode mysql_preparer : 0.42464170455933 ms, soit : 0.00042464170455933 secondes (ou encore 0.070773617426554 min) [4.2464170455933 secondes pour 10000]
            Methode pdo : 0.23174250125885 ms, soit : 0.00023174250125885 secondes (ou encore 0.038623750209808 min) [2.3174250125885 secondes pour 10000]
            Methode pdo_preparer : 0.23368623256683 ms, soit : 0.00023368623256683 secondes (ou encore 0.038947705427806 min) [2.3368623256683 secondes pour 10000]
        
    
    100 000 enregistrements
    
        PAS DE WHERE
        trop long...
        
        WHERE id=26
            Methode mysql : 0.24360015153885 ms, soit : 0.00024360015153885 secondes (ou encore 0.40600025256475 min) [24.360015153885 secondes pour 100000]
            Methode mysql_preparer : 0.22027158260345 ms, soit : 0.00022027158260345 secondes (ou encore 0.36711930433909 min) [22.027158260345 secondes pour 100000]
            Methode pdo : 0.26385932683945 ms, soit : 0.00026385932683945 secondes (ou encore 0.43976554473241 min) [26.385932683945 secondes pour 100000]
            Methode pdo_preparer : 0.26255201339722 ms, soit : 0.00026255201339722 secondes (ou encore 0.43758668899536 min) [26.255201339722 secondes pour 100000]
            
        
        
    INSERT
        Methode mysql : 0.12988210678101 ms, soit : 0.00012988210678101 secondes (ou encore 0.21647017796834 min) [12.988210678101 secondes pour 100000]
        Methode mysql_preparer : 0.1372592830658 ms, soit : 0.0001372592830658 secondes (ou encore 0.22876547177633 min) [13.72592830658 secondes pour 100000]
        Methode pdo : 0.13123644113541 ms, soit : 0.00013123644113541 secondes (ou encore 0.21872740189234 min) [13.123644113541 secondes pour 100000]
        Methode pdo_preparer : 0.12584869146347 ms, soit : 0.00012584869146347 secondes (ou encore 0.20974781910578 min) [12.584869146347 secondes pour 100000]

        
        
InnoDB

    INSERT
        Methode mysql : 0.12481915950775 ms, soit : 0.00012481915950775 secondes (ou encore 0.020803193251292 min) [1.2481915950775 secondes pour 10000]
        Methode mysql_preparer : 0.14559719562531 ms, soit : 0.00014559719562531 secondes (ou encore 0.024266199270884 min) [1.4559719562531 secondes pour 10000]
        Methode pdo : 0.13333940505981 ms, soit : 0.00013333940505981 secondes (ou encore 0.022223234176636 min) [1.3333940505981 secondes pour 10000]
        Methode pdo_preparer : 0.13565442562103 ms, soit : 0.00013565442562103 secondes (ou encore 0.022609070936839 min) [1.3565442562103 secondes pour 10000]

Donc j'avoue ne pas comprendre pourquoi les requêtes préparer, qui comme leur nom l'indique sont censé être préparer et plus rapide, sont ici beaucoup plus lente que les versions "normales"??
Je me demande s'il n'y a pas des mécanismes interne qui fausse ces résultats? Quelqu'un pourrait m'éclairer peut être?

Sinon, que pensez-vous du fait que mysql_query > pdo? Quel conclusion en prendre? Et surtout, au final, que choisir?

En espérant que le débat restera ouvert.


RE: [Test Performence] Requetes SQL - Anthor - 31-03-2011

C'est comme une pizza surgelé, c'est plus rapide à manger mais pas forcement de meilleure qualité...


RE: [Test Performence] Requetes SQL - Argorate - 31-03-2011

Oui, enfin, ce n'est pas une petite différence a certains endroit... Es-ce vraiment à négliger?


RE: [Test Performence] Requetes SQL - Anthor - 31-03-2011

Je ne peux rien dire, vu que tu ne fournis rien ^^

Dans quelles conditions fais-tu ton test ? Avec quelle plateforme ?
Les 4 à la suite à l'arrache ? Sous windows (HAHAHAHA) ?



RE: [Test Performence] Requetes SQL - Argorate - 31-03-2011

J'ai fais ça en local, avec wamp sur un windows XP et les 4 à la suite
J'ai rien à cacher, mon but est de comprendre... ^^
Cependant même si les conditions ne sont pas optimale, puisqu'elles sont les même pour chaque test, tout les écarts possible sont ajouter à chaque test, donc au final la différence reste la même.

EDIT: C'est bon j'ai compris pourquoi ces résultats ne me semblait pas cohérent, petite erreur d'étourderie, j'arrange ça et je met à jour Smile (le temps de refaire les tests ^^)
EDIT2: code déplacer dans le premier topic et corrigé.


RE: [Test Performence] Requetes SQL - niahoo - 31-03-2011

Ben déjà pourquoi tu calcules le temps à chaque itération. il faut le mettre à l'intérieur de ton while.

Si c'est juste pour éviter de calculer le temps de passage en paramètre du PDOStatement, je te conseille de faire un benchmark plus simple. là, l'intérêt de jouer sur les noms de tes méthodes et de parcourir un tableau c'est bien joli mais ça rend tout le test illisible.


RE: [Test Performence] Requetes SQL - Argorate - 31-03-2011

J'ai presque fini de refaire les tests sans ma bourde. Me manque plus qu'un résultat. J'éditerais en début d'aprem, les résultats semble beaucoup plus parlant! vive les requêtes préparer :roll:

Sinon, je calcule le temps uniquement de l'instruction que je veux tester, voilà pourquoi j'ai mis les microtime() dans chacune des fonctions, encadrant l'instruction qui lance la requête SQL. Au moins je ne perds pas quelques microseconde avant ou après, comme se serait le cas si je m'étais ça dans la boucle. (au final ça revient au même, c'est juste plus rigoureux à mon sens).
Après la lisibilité du truc n'était pas vraiment recherché, j'ai fait ça pour moi^^
Ce qui m'intéresse c'est les résultats, et les potentiels conclusion.
Cependant je ne vois pas ce qu'il y a de compliqué dans l'exécution du code que j'ai mis, c'est le fait de placer le nom de la fonction dans une variable qui te gène?


RE: [Test Performence] Requetes SQL - Sephi-Chan - 31-03-2011

Ce n'est pas comme ça qu'on mène des tests. Mieux vaut utiliser 4 scripts, lancés séparément (et donc dans des processus différents) et avec un peu de temps entre chaque (que la machine revienne à son état initial). Ça donne des résultats plus justes.

Sur un OS Unix, il y a une commande time qui peut être utile :


$ time php -e benchmark_mysql.php
$ time php -e benchmark_pdo.php
$ ...

D'ailleurs, il faudrait tester ça sur un OS Unix, car c'est bien ce genre d'environnement qu'on utilise en production avec PHP, pas du Windows.
Même s'il n'y a pas de différence ou qu'elles sont sensibles, c'est plus intelligent.


Sephi-Chan


RE: [Test Performence] Requetes SQL - Anthor - 31-03-2011

J'ajoute aussi à ce qu'à dit mon jambon, que MySQL windows c'est loin d'être une bête... Suffit de profiler sous windows et sous linux pour voir l'"énorme" différence !
Un serveur qui ne fait que ça, ce n'est pas un OS utilisateur ^^


RE: [Test Performence] Requetes SQL - niahoo - 31-03-2011

(31-03-2011, 12:08 PM)Argorate a écrit : Cependant je ne vois pas ce qu'il y a de compliqué dans l'exécution du code que j'ai mis, c'est le fait de placer le nom de la fonction dans une variable qui te gène?

Ce qui me gène c'est que le test n'est pas clair. généralement tu fais un script par test et tu les inclus dans ton benchmark pour les lancer. (Mais la méthode proposée par sephi me parait plus intéressante).

Bon c'est pour chipoter car les 4 méthodes se tiennent de près. Parfois tu as plusieurs méthodes candidates pour traiter un problème qui seront très différentes. c'est bien d'avoir un test clair qui te montre toute la méthode.

Par exemple, si je testais PDO, je mettrais la préparation de la requête dans la boucle. (Toi tu l'additionnes ensuite ce qui revient au même techniquement mais pas logiquement). si tu inclus une librairie ça compte aussi, etc.