Tema de debat => joins

1 view
Skip to first unread message

LLeïr Borràs

unread,
Dec 4, 2009, 9:39:46 AM12/4/09
to girona...@googlegroups.com
A veure, aixó ho podria "postejar" a la llista ror-es, però així
potser comencem a donar vidilla a la llista.

Donat:

class A < ActiveRecord::Base
has_many Bs
end

class B < ActiveRecord::Base
belongs_to A
end

Volem fer una consulta que ens doni totes les As tals que tinguin Bs,
i OBVIAMENT no volem As duplicats.

El primer que em bé al cap és

A.all(:joins => [Bs]) #simple, senzill i... erroni!

però...

A.all(:joins => [Bs]).size >= A.count

I que vol dir? Doncs com que rails està fent un "inner join" ens torna
molts resultats duplicats quant un A tingui varis Bs.

Per arreglar aixó se m'ocurreix?

A.all(:joins => [Bs], :group => :id) #Funciona, però un "group by"
sol ser lent, i si hi ha més condicions...

A.all(:joins => [Bs], :select => "distinct(as.*)") #Funciona, però
generem acoblament...

B.all.collect{|b| b.a}.uniq #Funciona, però és lent i guarro de collons


Arribats a aquest punt... quina és la millor solució que se us
ocurreix / feu servir? Segurament pensareu que és una pregunta xorra,
però em toca els nassos haver de fer coses rares al mig del codi.

Apale fins ara

--
Lleïr Borràs i Metje
http://lleirborras.blogspot.com
http://twitter.com/lleirborras
http://github.com/lleirborras

Iván Belmonte

unread,
Dec 4, 2009, 10:28:53 AM12/4/09
to girona...@googlegroups.com
Hola

Jo soc un patata programant i segur que la cago, pero no es podria fer
aixi?

B.all(:select => 'DISTINCT(a_id)')

Salu2

--
Real_men_dont_need_spacebars

LLeïr Borràs

unread,
Dec 4, 2009, 10:46:00 AM12/4/09
to girona...@googlegroups.com

Jo vull As ;-)

Lleir Borras Metje

El 04/12/2009 16:28, "Iván Belmonte" <iv...@ivanhq.net> escribió:


Hola

Jo soc un patata programant i segur que la cago, pero no es podria fer
aixi?

  B.all(:select => 'DISTINCT(a_id)')

Salu2

--
Real_men_dont_need_spacebars

On Dec 4, 2009, at 15:39 , LLeïr Borràs wrote: > > A veure, aixó ho podria "postejar" a la llista ...


Iván Belmonte

unread,
Dec 4, 2009, 11:08:20 AM12/4/09
to girona...@googlegroups.com
On Dec 4, 2009, at 15:39 , LLeïr Borràs wrote:

> Volem fer una consulta que ens doni totes les As tals que tinguin Bs,
> i OBVIAMENT no volem As duplicats.
>
> El primer que em bé al cap és
>
> A.all(:joins => [Bs]) #simple, senzill i... erroni!

-- I pq es erroni aixo?


Iván Belmonte

unread,
Dec 4, 2009, 11:29:24 AM12/4/09
to girona...@googlegroups.com
Vale, he tornat a llegir el teu correo original, ja entenc per que dius que és erroni... ja nava a dirte el :group heheh...

res res, la pregunta segueix oberta heheh

--
Real_men_dont_need_spacebars

Iván Belmonte

unread,
Dec 4, 2009, 11:32:00 AM12/4/09
to girona...@googlegroups.com
On Dec 4, 2009, at 15:39 , LLeïr Borràs wrote:

> Per arreglar aixó se m'ocurreix?
>
> A.all(:joins => [Bs], :group => :id) #Funciona, però un "group by"
> sol ser lent, i si hi ha més condicions...

-- Home jo crec que aquesta es l'unica manera. Ara, si necessites
performance hauries d'utilitzar un indexador crec, no?

--
Real_men_dont_need_spacebars

Josep Segura

unread,
Dec 4, 2009, 12:49:50 PM12/4/09
to girona...@googlegroups.com
Si et va be utilitzar counter cache, que tal així?

A.all, :conditions => ‘bs_count > 0’




2009/12/4 LLeïr Borràs <mem...@gmail.com>

Josep Segura

unread,
Dec 4, 2009, 12:51:47 PM12/4/09
to girona...@googlegroups.com
Millor sense la coma ;-)

A.all :conditions => ‘bs_count > 0’



2009/12/4 Josep Segura <josep...@gmail.com>

Emili Parreño

unread,
Dec 6, 2009, 5:19:04 AM12/6/09
to girona...@googlegroups.com
Jo cada cop que sento inner join em poso a tremolar :) pel cas que has explicat ( no se si pot tenir altres implicacions) faria el que proposa en Pep, fer servir un counter_cache, la query serà rapida i si ho poses en un named_scope el codi quedarà net.
--
-------------------------------------------------
Emili Parreño - www.eparreno.com
ProRuby - www.prorubyteam.com
-------------------------------------------------

Rafael Pallares

unread,
Dec 6, 2009, 6:26:21 AM12/6/09
to girona...@googlegroups.com
Jo diria, que en la seguent instruccio

A.all :conditions => ‘bs_count > 0’

Rails, el que fa es fer un group by de b per a_id i fer un joins en
memoria amb A. Entenc que si hi han pocs registres es una solucio
bona. Pero si hi han molt registres aixo te un cost alt en la BBDD i
mes, si en el group by no s'aplica el where corresponent.

A nivell de SQL, el que jo utilitzaria serien SUBSELECT:
select A.id, A.code from A where A.id in (select distinct B.a_id from B)

El que ara no se fer encara en rails, es implementar aquest SUBSELECT.

Rafa.


El 06/12/09, Emili Parreño <emili....@gmail.com> ha escrit:
--
Fins Aviat.
Rafa

Emili Parreño

unread,
Dec 6, 2009, 4:05:59 PM12/6/09
to girona...@googlegroups.com


2009/12/6 Rafael Pallares <rpc...@gmail.com>


Jo diria, que en la seguent instruccio

A.all :conditions => ‘bs_count > 0’

Rails, el que fa es fer un group by de b per a_id i fer un joins en
memoria amb A. Entenc que si hi han pocs registres es una solucio
bona. Pero si hi han molt registres aixo te un cost alt en la BBDD i
mes, si en el group by no s'aplica el where corresponent.

No es exactament així. Si fas  servir counter_cache d'aquesta manera

class A < AR
has_many :Bs
end

class B < AR
belongs_to A, :couner_cache => true
end

Si tenim un atribut al model A que es digui bs_count, cada cop que es crea un registre de la classe B, s'augmenta el contador bs_count. Es una solució per evitar contar, per exemple, quants comentaris té un post, cada vegada que ho vols saber. En aquest cas també serveix ja que si el contador es mes gran que 0 vol dir que hi hi alguna B que pertany a aquella A , que en principi era el que volia saber en Lleïr

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001833
http://railscasts.com/episodes/23-counter-cache-column

Reply all
Reply to author
Forward
0 new messages