2010-01-29 12 views
5

J'ai une requête de calcul de compte que je cours des milliers de fois dans mon application Rails, une fois pour chaque client dans la DB.Rails MySQL requête confusion de temps

Lorsque j'exécute la requête dans mon client MySQL avec le cache de requête désactivé, la requête dure 1ms. Cependant, lorsque j'exécute ma tâche à partir de la console Rails avec la sortie de requête activée, j'ai remarqué qu'après les premières requêtes qui sont très rapides, le temps passe soudain de moins de 1 ms à environ 180 ms pour le reste de la requêtes.

J'ai réduit l'innodb_buffer_pool_size afin de voir un changement de comportement mais je n'ai rien remarqué.

est ici la sortie de la console:

EmailCampaignReport::Open Columns (143.2ms) SHOW FIELDS FROM `email_campaign_report_opens` 
    SQL (0.3ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332330) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 333333) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332661) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332326) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332665) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 336027) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 333001) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 331983) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332668) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332316) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332325) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 331995) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 334007) 
    SQL (0.2ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 333326) 
    SQL (0.1ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332998) 
    SQL (183.9ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 334673) 
    SQL (183.7ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 336751) 
    SQL (183.6ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 333334) 
    SQL (186.3ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332663) 
    SQL (183.7ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332328) 
    SQL (186.3ms) SELECT count(*) AS count_all FROM `email_campaign_report_opens` WHERE (customer_id = 332659) 

Il y a un index sur la colonne customer_id dans ce tableau.

Quelqu'un at-il des suggestions pour expliquer pourquoi cela se produirait?

Merci

+0

Pouvez-vous poster votre schéma de table afin que nous puissions voir l'index etc? – UltimateBrent

Répondre

4

Pourquoi ne pas exécuter une seule requête?

SELECT customer_id, count(*) AS count_all FROM `email_campaign_report_opens` GROUP BY customer_id; 

Si vous avez tant de dossiers que vous êtes inquiet pour les retourner tout alors le faire par lots, mais je ne comprends pas pourquoi vous voulez vraiment exécuter cette requête pour chaque client.

+0

pourquoi je n'ai pas pensé à ça! Merci mec. – johnnymire

+0

Content que cela fonctionne pour vous. Il est facile d'avoir l'esprit de tout faire avec des objets et des itérateurs dans ActiveRecord, mais parfois un peu de SQL est le meilleur. –

0

Est-ce que cela se produise dans vos rails app aussi bien, ou que cela arrive tout simplement lorsque vous exécutez dans la console? En outre, utilisez-vous un client tel que Aptana ou exécutez-vous ceci dans un shell?

+0

Cela a été exécuté dans un shell et cela se produit également dans l'application Rails. – johnnymire

0

Quelle est la version de Rails? Selon votre version et votre code Ruby/Rails, il se peut que vous mettiez en cache un grand nombre de données sans l'utiliser, et après un certain temps, il doit effectuer une récupération avant d'obtenir de nouvelles données, ce qui peut expliquer le retard. Ceci est une supposition, faites attention à vous.

+0

It's Rails version 2.3.2 – johnnymire

0

Ne serait-il pas logique d'ajouter un counter cache à l'association (lire: ajouter un email_campaign_report_opens_count à votre modèle Customer)? Bien sûr, vous devez initialiser les compteurs pendant la migration, mais alors il devrait être très rapide et vous n'avez même pas besoin de toucher la table associée tout en marchant à la table des clients.

+0

Bonne suggestion. C'était presque ce que je faisais, j'ai un champ de compte similaire dans le modèle client qui était mis à jour par ce script en obtenant tous les comptes. La mise à jour du cache de compteur au fur et à mesure que les associations sont créées peut être meilleure. Vous aurez toujours le problème de vitesse de requête lors de la migration initiale, mais au moins c'est une fois une. – johnnymire