2009-12-05 5 views
4

Y a-t-il une différence appréciable de performances entre une requête SELECT foo, bar, FROM users qui renvoie 500 lignes et 500 requêtes SELECT foo, bar, FROM users WHERE id = x qui arrivent toutes en même temps?Frais généraux pour MySQL SELECTS - Mieux vaut en utiliser un ou plusieurs en séquence

Dans une application PHP que j'écris, j'essaie de choisir entre une section de code claire et lisible qui produirait environ 500 instructions SELECT; ou en l'écrivant d'une manière obscure et complexe qui n'utiliserait qu'un seul SELECT qui renvoie 500 lignes. Je préférerais la façon dont le code est clair et maintenable, mais je crains que la surcharge de connexion pour chacun des SELECT entraînera des problèmes de performance.

information de fond, dans le cas où il est pertinent: 1) Ceci est un module Drupal, codé en PHP 2) Les tableaux en question deviennent très peu INSERTs et mises à jour et sont rarement verrouillé 3) SQL JOIN ne sont pas possible pour des raisons sans rapport avec la question

Merci!

Répondre

9

Il est presque toujours plus rapide de faire un gros batch SELECT et d'analyser les résultats dans votre code d'application que de faire un grand nombre de SELECT pour une ligne. Je recommanderais que vous implémentez les deux et les profilez, cependant. Toujours s'efforcer de minimiser le nombre d'hypothèses que vous avez à faire.

+0

Merci! Je m'en doutais autant. Pourriez-vous donner une idée de * pourquoi * c'est mieux cependant, par exemple à cause des frais généraux de connexion? Je voudrais avoir une meilleure compréhension de comment exactement une façon est meilleure. – anschauung

+3

La CPU et la mémoire sont toujours moins coûteuses que n'importe quelle forme d'E/S, y compris les E/S réseau. Pensez-y comme ceci: il est certainement moins cher d'envoyer une seule commande pour 500 livres et de les recevoir dans un paquet énorme par la poste, que d'envoyer 500 commandes et de recevoir tous les livres dans un emballage séparé. :) –

1

Il semble que vous savez ce que les 500 id valeurs sont, alors pourquoi ne pas faire quelque chose comme ceci:

// Assuming you have already validated that this array contains only integers 
// so there is not risk of SQl injection 

$ids = join(',' $arrayOfIds); 

$sql = "SELECT `foo`, `bar` FROM `users` WHERE `id` IN ($ids)"; 
+0

Je ne connais pas les identifiants dans ce cas, mais c'est une technique soignée. Je vais devoir m'en souvenir. – anschauung

+0

Si vous n'avez pas d'ID, comment pouvez-vous exécuter 'SELECT foo, bar, FROM utilisateurs WHERE id = x'? –

+0

Je vois ce que tu veux dire. Ce que je voulais écrire, c'est que je peux * obtenir * les identifiants, mais le moyen le plus simple de le faire est de les obtenir un à la fois. Je ne les ai pas tous dans un lot pratique. – anschauung

3

Je ne vous inquiétez pas au sujet de la surcharge de connexion des requêtes MySQL trop, surtout si vous n'êtes pas fermer la connexion entre chaque requête. Considérez que si votre requête crée une table temporaire, vous avez déjà passé plus de temps dans la requête que la surcharge de la requête. J'aime faire une requête SQL complexe, personnellement, mais j'ai trouvé que la taille des tables, le cache de requêtes mysql et les performances de requête des requêtes qui ont besoin de vérifier la distance (même par rapport à un index) font toutes la différence.

Je propose ceci:

1) Établir simple, la ligne de base correcte. Je pense que c'est l'approche de zillion-query. Ce n'est pas faux, et très vraisemblablement correct. Exécutez-le plusieurs fois et observez le cache de vos requêtes et les performances de vos applications. La possibilité de maintenir votre application à portée de main est très importante, surtout si vous travaillez avec d'autres responsables du code. En outre, si vous interrogez des tables très volumineuses, les petites requêtes maintiendront l'évolutivité.

2) Code de la requête complexe. Comparez les résultats pour la précision, puis l'heure. Utilisez ensuite EXPECT sur la requête pour voir quelles sont les lignes analysées. J'ai souvent constaté que si j'ai un JOIN, ou un WHERE x! = Y, ou une condition qui crée une table temporaire, les performances de la requête pourraient être très mauvaises, surtout si je suis dans une table qui est toujours mise à jour. Cependant, j'ai également constaté qu'une requête complexe peut ne pas être correcte, et qu'une requête complexe peut être plus facilement interrompue à mesure qu'une application se développe. Les requêtes complexes analysent généralement des ensembles de lignes plus importants, créant souvent des tables temporaires et appelant des analyses using where. Plus la table est grande, plus ils sont chers. En outre, vous pouvez avoir des considérations d'équipe lorsque des requêtes complexes ne correspondent pas aux points forts de votre équipe.

3) Partagez les résultats avec votre équipe.

Les requêtes complexes sont moins susceptibles de toucher le cache de requête mysql, et si elles sont assez grandes, ne les cachez pas. (Vous voulez enregistrer le cache de requête mysql pour les requêtes fréquemment rencontrées.) De plus, interrogez les prédicats qui doivent balayer l'index. (x! = y, x> y, x < y). Des requêtes comme SELECT foo, bar FROM users WHERE foo != 'g' and mumble < '360' finissent par faire des scans. (Le coût du surdébit de requête peut être négligeable dans ce cas.)

Les petites requêtes peuvent souvent aboutir sans créer de tables temporaires en obtenant toutes les valeurs de l'index, à condition que les champs que vous sélectionnez et que vous prédiciez soient indexés . Ainsi, les performances des requêtes de SELECT foo, bar FROM users WHERE id = x est vraiment super (surtout si les colonnes foo et bar sont indexés comme, alias alter table users add index ix_a (foo, bar);.)

D'autres bonnes façons d'augmenter les performances de votre application serait de mettre en cache les petits résultats de la requête dans l'application (si approprié), ou en effectuant des tâches par lots d'une requête de vue matérialisée. En outre, considérez memcached ou certaines fonctionnalités trouvées dans XCache.

+0

Bon conseil. Je n'ai fait que comparer des requêtes alternatives où le plus petit lot de requêtes comparables s'exécutait 5 fois plus vite que la grosse requête complexe. – kingjeffrey

+0

Bien que le conseil général ici soit bon, dire ne pas s'inquiéter de la surcharge de connexion en utilisant php avec mysql n'est absolument pas correct. Essayez un benchmark sur la situation décrite et vous verrez que faire 500 petites requêtes contre 1 grosse aura une énorme différence. La méthode de requête peut être environ 50 fois plus rapide que la méthode de requête multiple. – Zaptree

Questions connexes