2010-01-29 12 views
5

Ho una query di calcolo del conteggio che sto eseguendo migliaia di volte nella mia app Rails, una volta per ogni cliente nel db.Rails MySQL query confusion time

Quando si esegue la query nel mio client MySQL con cache di query disattivata, la query impiega più di 1 ms.

Tuttavia, quando eseguo il mio compito dalla console Rails con l'output della query abilitato, ho notato che dopo le prime query che sono molto veloci, il tempo improvvisamente aumenta da meno di 1 ms a circa 180 ms per il resto del interrogazioni.

Ho ridotto il parametro innodb_buffer_pool_size per vedere un cambiamento nel comportamento ma non ho notato nulla.

Ecco l'output dalla 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) 

C'è un indice sulla colonna customer_id in tale tabella.

Qualcuno ha qualche suggerimento sul perché questo sta accadendo?

Grazie

+0

Puoi pubblicare lo schema della tabella in modo che possiamo vedere l'indice ecc.? – UltimateBrent

risposta

4

Perché non eseguire solo una query?

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

Se si dispone di così tanti dischi che si sono preoccupati per il ritorno a tutti poi lo fanno in lotti, ma io proprio non si capisce perché si vuole veramente per eseguire la query per ogni cliente.

+0

perché non ci ho pensato! Grazie uomo. – johnnymire

+0

Felice che funzioni per te. È facile entrare nella mentalità di fare tutto con oggetti e iteratori in ActiveRecord, ma a volte un po 'di SQL è il migliore. –

0

Questo accade nelle vostre rotaie app pure, o questo capita quando lo si esegue nella console? Inoltre, stai usando un client come Aptana o stai eseguendo questo in una shell?

+0

Questo è stato eseguito in una shell e si verifica anche nell'app Rails. – johnnymire

0

Quale versione di Rails è questa? A seconda della versione e del codice Ruby/Rails, è possibile che si memorizzino nella cache molti dati senza usarli, e dopo un po 'deve eseguire la garbage collection prima di ottenere nuovi dati, il che potrebbe spiegare il ritardo. Questa è una supposizione, intendiamoci.

+0

It's Rails versione 2.3.2 – johnnymire

0

Non avrebbe senso aggiungere un counter cache all'associazione (leggi: aggiungere un email_campaign_report_opens_count al modello Customer)? Naturalmente è necessario inizializzare i contatori durante la migrazione, ma dovrebbe essere molto veloce e non è nemmeno necessario toccare la tabella associata mentre si cammina la tabella dei clienti.

+0

Buon suggerimento. Questo era quasi ciò che stavo facendo, ho un campo di conteggio simile nel modello del cliente che veniva aggiornato da questo script ottenendo tutti i conteggi. L'aggiornamento della cache del contatore durante la creazione delle associazioni potrebbe essere migliore. Avrà ancora il problema di velocità della query durante la migrazione iniziale, ma almeno è una volta. – johnnymire