2009-03-27 6 views
2

MISE À JOUR: inclure les relations modèleRails table de jointure rend mauvaise sql

J'ai plusieurs à plusieurs table de jointure entre les bandes et événements (un événement a de nombreux groupes, un groupe a beaucoup d'événements ...)

J'ai une page principale qui répertorie tous les événements, et une page récente qui affiche les événements mis à jour au cours des 7 derniers jours.

Quelqu'un pourrait-il expliquer pourquoi la méthode récente génère sql parfaite avec toutes les jointures inclus

@events = Event.find(:all, :include => [:venue, :bands], :conditions => {:updated_at => d1..DateTime.now}, :order => 'events.updated_at desc') 

Et la principale méthode génère sql horrible interroge la table de bande pour chaque événement. Ils utilisent tous deux la même vue, il n'y a pas d'autre traitement/interrogation en cours. La seule différence entre les deux est le paramètre: conditions et la colonne sur laquelle il est trié. Ça me rend fou!

Désolé, voici mes modèles et leurs relations

event.rb

has_many :event_bands 
has_many :bands, :through => :event_bands 
belongs_to :venue 

band.rb

has_many :event_bands 
has_many :events, :through => :event_bands 

event_bands.rb

belongs_to :event 
belongs_to :band 

SQL généré par Récent:

Processing EventlistController#recent (for 127.0.0.1 at 2009-03-27 14:58:10) [GET] 
    [4;35;1mSQL (0.0ms)[0m [0mSET SQL_AUTO_IS_NULL=0[0m 
    [4;36;1mEvent Columns (16.0ms)[0m [0;1mSHOW FIELDS FROM `events`[0m 
    [4;35;1mVenue Columns (15.0ms)[0m [0mSHOW FIELDS FROM `venues`[0m 
    [4;36;1mBand Columns (16.0ms)[0m [0;1mSHOW FIELDS FROM `bands`[0m 
    [4;35;1mEvent Load Including Associations (31.0ms)[0m [0mSELECT `events`.`id` AS t0_r0, `events`.`is_local` AS t0_r1, `events`.`link` AS t0_r2, `events`.`notes` AS t0_r3, `events`.`band_id` AS t0_r4, `events`.`venue_id` AS t0_r5, `events`.`created_at` AS t0_r6, `events`.`updated_at` AS t0_r7, `events`.`day` AS t0_r8, `events`.`band_list` AS t0_r9, `venues`.`id` AS t1_r0, `venues`.`name` AS t1_r1, `venues`.`link` AS t1_r2, `venues`.`map` AS t1_r3, `venues`.`notes` AS t1_r4, `venues`.`created_at` AS t1_r5, `venues`.`updated_at` AS t1_r6, `bands`.`id` AS t2_r0, `bands`.`name` AS t2_r1, `bands`.`link` AS t2_r2, `bands`.`notes` AS t2_r3, `bands`.`is_local` AS t2_r4, `bands`.`created_at` AS t2_r5, `bands`.`updated_at` AS t2_r6 FROM `events` LEFT OUTER JOIN `venues` ON `venues`.id = `events`.venue_id LEFT OUTER JOIN `event_bands` ON (`events`.`id` = `event_bands`.`event_id`) LEFT OUTER JOIN `bands` ON (`bands`.`id` = `event_bands`.`band_id`) WHERE (`events`.`updated_at` BETWEEN '2009-03-20 14:58:10' AND '2009-03-27 14:58:10') 

sql générés par les principales

Processing EventlistController#index (for 127.0.0.1 at 2009-03-27 14:15:47) [GET] 
    [4;35;1mSQL (0.0ms)[0m [0mSET SQL_AUTO_IS_NULL=0[0m 
    [4;36;1mEvent Load (0.0ms)[0m [0;1mSELECT * FROM `events` ORDER BY events.day[0m 
    [4;35;1mEvent Columns (15.0ms)[0m [0mSHOW FIELDS FROM `events`[0m 
    [4;36;1mVenue Columns (16.0ms)[0m [0;1mSHOW FIELDS FROM `venues`[0m 
    [4;35;1mVenue Load (0.0ms)[0m [0mSELECT * FROM `venues` WHERE (`venues`.`id` IN (6,7,8,9,1,2,3,4,5)) [0m 
    [4;36;1mEventBand Load (0.0ms)[0m [0;1mSELECT `event_bands`.* FROM `event_bands` WHERE (`event_bands`.event_id IN (1,24,74,2,75,11,12,3,13,129,76,14,77,78,145,4,146,120,15,130,79,147,5,80,148,144,131,81,132,16,28,82,121,133,83,17,134,84,149,6,18,135,85,122,19,7,136,86,20,9,87,25,137,150,22,138,88,151,124,123,139,89,152,140,90,141,91,8,153,21,142,154,125,143,92,126,10,93,94,155,127,95,128,23,96,97,26,98,99,27,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119)) [0m 
    [4;35;1mEventBand Columns (0.0ms)[0m [0mSHOW FIELDS FROM `event_bands`[0m 
    [4;36;1mBand Columns (16.0ms)[0m [0;1mSHOW FIELDS FROM `bands`[0m 
    [4;35;1mBand Load (0.0ms)[0m [0mSELECT * FROM `bands` WHERE (`bands`.` 
+0

Quel sql le premier génère-t-il si vous enlevez: des conditions? Cela vous dirait au moins si cela est dû aux: conditions ou à: l'ordre. –

+0

Encore mieux, postez le sql généré par les deux exemples. En outre, quelle version de rails utilisez-vous, parce que c'est une zone qui a été en mouvement ces derniers mois. – MarkusQ

+0

Ce n'est pas l'ordre, le sql reste le même si j'enlève ça. J'utilise des rails 2.2.2 – Luke

Répondre

3

La raison pour laquelle ils génèrent deux requêtes SQL différentes est que Rails, par défaut, tente d'optimiser vos requêtes SQL pour moins jointures. Lorsque vous incluez une liste de conditions dans le cadre de votre recherche qui nécessite l'utilisation d'autres tables, le SQL résultant doit bien entendu inclure une jointure. Mais si tout ce que vous demandez est de pré-remplir des objets avec des relations avec les objets que vous récupérez, alors Rails pense qu'il est plus efficace d'effectuer plusieurs requêtes rapides plutôt qu'une grande requête lente. Notez que cela ne provoque pas de problème N + 1, car Rails tentera de charger tous les enregistrements associés dans une requête unique.

+0

Merci, cela a du sens. Donc, votre recommandation serait de simplement laisser ActiveRecords faire sa chose? – Luke

+0

Probablement, ouais. Par tous les moyens, écrivez le SQL personnalisé si vous avez besoin; ActiveRecord ne peut pas résoudre tous les problèmes du monde. Mais dans ce cas particulier, il y a, en fait, une raison pour la folie. –

+0

Naturellement. J'étais juste vraiment confus par les résultats de cette simple jointure. Merci! – Luke

Questions connexes