7
votes

Les déclarations ne devraient pas être beaucoup plus rapides?

$s = explode (" ", microtime());
$s = $s[0]+$s[1];
$con = mysqli_connect ('localhost', 'test', 'pass', 'db') or die('Err');

for ($i=0; $i<1000; $i++) {

  $stmt = $con -> prepare( " SELECT MAX(id) AS max_id , MIN(id) AS min_id FROM tb ");
  $stmt -> execute();
  $stmt->bind_result($M,$m);
  $stmt->free_result();
  $rand = mt_rand( $m , $M ).'<br/>';

  $res = $con -> prepare( " SELECT * FROM tb WHERE id >= ? LIMIT 0,1 ");
  $res -> bind_param("s", $rand);
  $res -> execute();
  $res->free_result();
}

$e = explode (" ", microtime());
$e = $e[0]+$e[1];
echo  number_format($e-$s, 4, '.', '');

// and:

$link = mysql_connect ("localhost", "test", "pass") or die ();
mysql_select_db ("db") or die ("Unable to select database".mysql_error());

for ($i=0; $i<1000; $i++) {
  $range_result = mysql_query( " SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM tb ");
  $range_row = mysql_fetch_object( $range_result ); 
  $random = mt_rand( $range_row->min_id , $range_row->max_id );
  $result = mysql_query( " SELECT * FROM tb WHERE id >= $random LIMIT 0,1 ");
}
defenitly prepared statements are much more safer
but also every where it says that they are much faster
BUT in my test on the above code I have:
- 2.45 sec for prepared statements
- 5.05 sec for the secon exampleWhat do you think I'm doing wrong?
Should I use the second solution or I should try to optimize the prep stmt?

5 commentaires

2.45 est plus rapide que 5,05?


Veuillez formater le code de sorte qu'il soit lisible.


Omg .. Les gens ne peuvent rien comprendre si vous écrivez comme ça .. Format-le correctement.


Je viens de remarquer après la modification que vous préparez également les déclarations chaque fois à travers la boucle. Tout cela est que vous n'avez besoin que de les préparer une fois.


Désolé pour l'erreur qu'il s'agissait de 2,45 pour Sol2 et 5 sec pour la société de préparation


4 Réponses :


4
votes

Il n'y a aucun avantage à préparer une déclaration à l'intérieur d'une boucle pour une seule exécution. Vous ne faites que ajouter des frais généraux. Utilisez des énoncés préparés pour les requêtes que vous exécutez généralement généralement avec différents paramètres.


3 commentaires

Oui, il s'agissait bien d'une énorme erreur de mettre préparé la STMT à l'intérieur de la boucle, mais après avoir mis les deux préparez à Otside la boucle, le résultat est de 2,39sec qui est que 3% de vitesse augmente de vitesse ne devrait pas être plus?


pas nécessairement. L'économie principale provient de la composition d'un plan de requête pour la requête. Si c'est une déclaration SQL triviale, il n'y a pas beaucoup à sauver. Rien n'est vraiment compilé, donc il n'y a vraiment pas de cycles de CPU à en parler, et si votre requête frappe le disque du tout (c'est-à-dire que les données ne sont pas cachées) qui marquent rapidement toutes les économies de cycle - les accès des disques sont tellement plus lents. que les cycles de la CPU.


La DB n'est pas si grosse ce n'est que 42.000, mais j'espérais beaucoup plus d'économies. Mais probablement vous avez Wright.



25
votes

Qu'est-ce que vous faites mal, c'est que vous préparez la déclaration mille fois et ne gère que chaque déclaration préparée une fois. Vous devriez le préparer une fois et l'exécuter mille fois.


5 commentaires

Pour être plus clair, vous devez la préparer une fois, puis la liaison et l'exécuter mille fois.


C'est ce qui se passe lorsque les gens ne comprennent pas le concept d'invariants dans des boucles: - /


J'ai mis les deux déclarations préparées à l'esprit de la boucle et maintenant, j'ai maintenant environ 2,39 sec et à Sol.2 j'avais 2,45. Est-ce normal? C'est juste une amélioration de 3%.


Vous devez exécuter des tests parfois de sorte que la base de données soit "réchauffée". La base de données met en cache le résultat. Le deuxième test utilisera donc les données en cache du premier test, ce qui lui confère un avantage injuste. En outre, vous ne mesurez pas seulement le temps d'exécution, qui ne montre pas la charge de la base de données pendant l'exécution.


Je vois, donc ce n'est pas le meilleur test de mesurer le diff entre les statistiques de Prep et la requête régulière. Merci beaucoup



1
votes

En plus des réponses ci-dessus ...

Je vois que vous utilisez MySQL et ci-dessous est le lien de là sur les déclarations préparées: http://dev.mysql.com/tech-resources/ Articles / 4.1 / Préparé-Status.html

Un extrait de là:

L'augmentation des performances dans des déclarations préparées peut provenir de quelques caractéristiques différentes. Premièrement, c'est la nécessité de n'étiliser que la requête une seule fois. Lorsque vous préparez initialement la déclaration, MySQL analysera la déclaration pour vérifier la syntaxe et configurer la requête à exécuter. Ensuite, si vous exécutez la requête plusieurs fois, cela n'aura plus ces frais généraux. Cette pré-analyse peut entraîner une augmentation de la vitesse si vous devez exécuter la même requête de plusieurs fois


4 commentaires

Comme je l'ai dit, je sais que c'était une grosse erreur de les mettre à l'intérieur de la boucle, mais après avoir mis $ con -> préparer () à l'extérieur, je n'obtiens que 3 à 5% de vitesse. J'étais attendu beaucoup plus, au moins 20-30% de vitesse d'incrée.


Pourquoi vous attendriez-vous à un tel% arbitraire d'augmentation de la vitesse? Les gains de performance et leurs mesures ne fonctionnent pas de cette façon. Cela dépend complètement de la taille des données que vous recherchez et sur le débit (voir ma réponse pour une meilleure explication.)


Pour ajouter à cela, je pense que vous devriez vous attendre à des gains sur l'utilisation de déclarations préparées à long terme et la santé de votre application sous forme d'objets moins temporaires créés lors de l'analyse. Pas sur des nombres d'exécution bruts. Et puisqu'il est rarement connu quand et comment une requête (ou tout élément de code) sera utilisée au fil du temps, il est préférable de leur faire toutes les déclarations préparées.


Pour Sigure, je vais utiliser la préparation de la préparation, mais je pensais que je faisais peut-être quelque chose de mal (à côté de la mise en préprette à l'intérieur de la boucle, ce qui était définitivement une énorme erreur). Et oui, mon% d'augmentation de la vitesse était basé sur ce que j'ai lu sur d'autres tutoriels et non sur des tests réels. Maintenant, je sous-estime que je m'attendais à trop pour ce genre de tests.



2
votes

@silversy -

Bases de boucle 101 (ou codage simple 101): Déplacez le code invariant de boucle hors des boucles. Pourquoi prépareriez-vous la déclaration dans la boucle lorsqu'il ne prendrait aucun paramètre dépendant de la boucle elle-même? P>

Bien sûr, il va sucer des gonades si vous utilisez des déclarations préparées si vous les préparez à chaque itération de la boucle. La surcharge que vous observez est dans la déclaration étant initialement préparée plutôt que dans son exécution. P>

re-fait votre code comme suit et réessayez à nouveau: P>

(A + Y)/(A + X) = 10.05sec/10.01sec ~=~ 1.004 


0 commentaires