# Alleggerire estrazione dati da tabella

**URL:** <https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726>\
**Category:** IT\
**Created:** [October 5, 2009, 2:13pm UTC](https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726 "2009-10-05T14:13:42Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![daneel\_olivaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/58f4c7/32.png) [@daneel\_olivaw](https://www.ruby-forum.com/u/daneel_olivaw)\
**Post date:** [October 5, 2009, 2:13pm UTC](https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726/1 "2009-10-05T14:13:42Z")

</div>

Salve lista.  
Ritorno su un’applicazione di cui avevo giÃ parlato tempo fa per  
chiedere aiuto su altri aspetti.

Tanto per capire un po’ cos’Ã¨ 'sta roba: ho un elenco di circa 20000  
elementi gestiti da degli operatori (una decina); per semplicitÃ le  
caratteristiche che l’operatore modifica sono salvate nella tabella  
dell’elemento, quindi la tabella degli elementi Ã¨ una cosa del genere:  
tabella objects (quella degli elementi in questione):

|id|user\_id|nomeoggetto|caratteristica1|caratt2|caratt3|…|carattn|

con legame 1 a molti tra la tabella users e objects.

Devo visualizzare delle statistiche di lavoro e in una delle quali devo  
mostrare quanti oggetti ha gestito ogni operatore e divisi oper  
caratteristica, quindi ho fatto una tabella del genere:

|--------------| oggetti |  
|nome\_operatore|caratt1|caratt2|caratt3|…|carattn|totale|  
|operatore1 | 10 | 23 | 131 |…| 3422 | 5335 |  
|operatore2 | 345 | 76 | 678 |…| 4321 | 6742 |  
…

La costruisco facendo nella vista una cosa del genere:

\<% for user in @user %\>

 \<%= user.login %\> \<% car1 = Objects.count(:conditions =\> "caratt1= '1'and user.id = '#{user.id}'") %\> \<% car2 = Objects.count(:conditions =\> "caratt2= '1'and user.id = '#{user.id}'") %\> ecc.

(sÃ¬, i campi sono quasi tutti booleani, o se non lo sono comunque mi  
serve la quantitÃ degli oggetti con quella caratteristica)

Prima al posto del count direttamente sulla tabella facevo cosÃ¬:

\<% car1 = @objects.map{|c| c if c.caratt1 == true c.user.id ==  
user.id}.compact.length %\>  
ecc.

in cui @objects era definito nel controller cosÃ¬: @objects =  
Object.find(:all)

Tra i due sistemi il primo mi genera la pagina in circa 8 secondi,  
mentre i secondo dai 18 ai 20.

C’Ã¨ un sistema piÃ¹ veloce e leggero per fare questa estrazione? E’ un  
po’ una seccatura trovarsi con la macchina che fa da serverino che  
rallenta di brutto ogni volta che il capogruppo va a vedersi le  
statistiche…

Grazie e a presto 🙂

---

<div class="post-metadata">

**Author:** ![daneel\_olivaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/58f4c7/32.png) [@daneel\_olivaw](https://www.ruby-forum.com/u/daneel_olivaw)\
**Post date:** [October 5, 2009, 2:49pm UTC](https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726/2 "2009-10-05T14:49:51Z")

</div>

Il 05 ottobre 2009 14.13, Daneel O. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha  
scritto:

> \<% for user in @user %\>
> 
> \<%= user.login %\> \<% car1 = Objects.count(:conditions =\> "caratt1= '1'and user.id = '#{user.id}'") %\> \<% car2 = Objects.count(:conditions =\> "caratt2= '1'and user.id = '#{user.id}'") %\>

il problema più grosso, qui, è che stai facendo una query alla volta  
(e ogni volta reinizi la connessione col db, mandi la query, aspetti  
il risultato e lo converti).

dovresti cercare di fare meno query. se stai usando mysql potresti fare  
così:  
@user = User.find\_by\_sql [“select _, (select count(_) from objects  
where objects.user\_id = users.id and caratt1=?) as car1, (select  
count(\*) from objects where objects.user\_id = users.id and caratt2=?)  
as car2) from users”, ‘1’, ‘1’]

poi puoi scrivere:

\<% for user in @user %\>  
\<%= user.login %\>  
\<%= user[‘car1’] %\>  
\<%= user[‘car2’] %\>  
\<% end %\>

in questa maniera ti colleghi al db una volta sola.

NOTA: ho provato qui da me ma con nomi diversi; riportando i nomi che  
hai usato tu potrei aver fatto errori di battitura e comunque non sono  
sicuro di aver capito cos’è “1” in “caratt1=‘1’”…

poi i dialetti sql cambiano, ma una cosa simile dovresti poterla fare  
per ogni dbms (anche se ti tocca fare query specifiche).

---

<div class="post-metadata">

**Author:** ![daneel\_olivaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/58f4c7/32.png) [@daneel\_olivaw](https://www.ruby-forum.com/u/daneel_olivaw)\
**Post date:** [October 5, 2009, 3:20pm UTC](https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726/3 "2009-10-05T15:20:47Z")

</div>

Pietro G. wrote:

> Il 05 ottobre 2009 14.13, Daneel O. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha  
> scritto:
> 
> > \<% for user in @user %\>  
> > ï¿½\<%= user.login %\>  
> > ï¿½\<% car1 = Objects.count(:conditions =\> “caratt1= '1’and user.id =  
> > ‘#{user.id}’”) %\>  
> > ï¿½\<% car2 = Objects.count(:conditions =\> “caratt2= '1’and user.id =  
> > ‘#{user.id}’”) %\>
> 
> il problema piï¿½ grosso, qui, ï¿½ che stai facendo una query alla volta  
> (e ogni volta reinizi la connessione col db, mandi la query, aspetti  
> il risultato e lo converti).

E comunque questo sistema Ã¨ molto piÃ¹ veloce che caricare tutta la  
tabella in un’array e poi analizzarla, come dicevo prima.

> dovresti cercare di fare meno query. se stai usando mysql potresti fare  
> cosï¿½:  
> @user = User.find\_by\_sql [“select _, (select count(_) from objects  
> where objects.user\_id = users.id and caratt1=?) as car1, (select  
> count(\*) from objects where objects.user\_id = users.id and caratt2=?)  
> as car2) from users”, ‘1’, ‘1’]

CioÃ¨ fare un’unica query in linguaggio sql in cui conto tutto ciÃ² che mi  
serve… wow! si vede che sono alle prime armi, non c’ero arrivato 🙂

> poi puoi scrivere:
> 
> \<% for user in @user %\>  
> \<%= user.login %\>  
> \<%= user[‘car1’] %\>  
> \<%= user[‘car2’] %\>  
> \<% end %\>
> 
> in questa maniera ti colleghi al db una volta sola.

ProverÃ².

> NOTA: ho provato qui da me ma con nomi diversi; riportando i nomi che  
> hai usato tu potrei aver fatto errori di battitura e comunque non sono  
> sicuro di aver capito cos’ï¿½ “1” in “caratt1=‘1’”…

Beh, ho semplificato brutalmente il codice, quindi sicuramente qualche  
boiata ci sarÃ .

Per quanto riguarda quel “caratt1=‘1’”, sta ad indicare che per  
quell’oggetto la caratteristica booleana “caratt1” ha valore “vero”,  
solo che se faccio una elaborazione in ruby posso definirlo  
semplicemente con “==true”, mentre se gli passo il comando sql ho visto  
che devo proprio dirgli “=‘1’”, altrimenti non funziona… almeno stando  
alla mia ben poca esperienza.

Grazie.

---

<div class="post-metadata">

**Author:** ![daneel\_olivaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/58f4c7/32.png) [@daneel\_olivaw](https://www.ruby-forum.com/u/daneel_olivaw)\
**Post date:** [October 7, 2009, 1:11pm UTC](https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726/4 "2009-10-07T13:11:22Z")

</div>

Il 07 ottobre 2009 12.39, Daneel O. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha  
scritto:

> Ah, c’è un errore dopo “car2” (che poi sarebbe lafine dell’ultimo  
> conteggio e passaggio alla variabile) non ci va la parentesi 🙂

mannaggia! 😛

> stringa… è normale?  
> Sì, è normale: il metodo find\_by\_sql è definito  
> così:  
> def find\_by\_sql(sql)  
> connection.select\_all(sanitize\_sql(sql), “#{name} Load”).collect! {  
> |record| instantiate(record) }  
> end

e tutti i metodi find usano find\_by\_sql.

Ad esempio, in un mio progetto c’è un modello Amount, un cui elemento  
(trovato con Amount.first) è questo:  
#\<Amount id: 1, attachment\_id: 174, tax\_base: 139.58, vat\_rate: 20.0,  
vat: 27.92, created\_at: “2008-11-07 15:58:56”, updated\_at: “2008-11-07  
15:58:56”\>

dalla connection però arriva questo:

{“vat\_rate”=\>“20”, “updated\_at”=\>“2008-11-07 15:58:56”,  
“attachment\_id”=\>“174”, “id”=\>“1”, “vat”=\>“27.92”,  
“tax\_base”=\>“139.58”, “created\_at”=\>“2008-11-07 15:58:56”}

È poi il metodo instantiate che fa le conversioni necessarie,  
basandosi sull’attributo columns, che contiene la definizione delle  
varie colonne.

pietro

---

<div class="post-metadata">

**Author:** ![daneel\_olivaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/58f4c7/32.png) [@daneel\_olivaw](https://www.ruby-forum.com/u/daneel_olivaw)\
**Post date:** [October 7, 2009, 12:39pm UTC](https://www.ruby-forum.com/t/alleggerire-estrazione-dati-da-tabella/176726/5 "2009-10-07T12:39:09Z")

</div>

Pietro G. wrote:

> dovresti cercare di fare meno query. se stai usando mysql potresti fare  
> cosï¿½:  
> @user = User.find\_by\_sql [“select _, (select count(_) from objects  
> where objects.user\_id = users.id and caratt1=?) as car1, (select  
> count(\*) from objects where objects.user\_id = users.id and caratt2=?)  
> as car2) from users”, ‘1’, ‘1’]

Provato e funziona: sono sui 9 secondi per generare la pagina.  
Ah, c’Ã¨ un errore dopo “car2” (che poi sarebbe lafine dell’ultimo  
conteggio e passaggio alla variabile) non ci va la parentesi 🙂

> poi puoi scrivere:
> 
> \<% for user in @user %\>  
> \<%= user.login %\>  
> \<%= user[‘car1’] %\>  
> \<%= user[‘car2’] %\>  
> \<% end %\>

CuriositÃ : dovendo anche generare i totali delle varie caratteristiche,  
io ho una cosa del genere:

\<% for user in @user %\>  
\<%= user.login %\>  
\<%= user[‘car1’] %\>  
\<% car1tot += user[‘car1’].to\_i %\>  
\<%= user[‘car2’] %\>  
\<% car2tot += user[‘car2’].to\_i %\>  
\<% end %\>  
…

Ho dovuto aggiungere il “to\_i” perchÃ© il dato cosÃ¬ com’Ã¨ Ã¨ visto come  
stringa… Ã¨ normale?
