views:

111

answers:

3

My understanding of the has_many relationship in Rails is that it will use a JOIN to find related rows. If I were implementing this from scratch I would have created a relational table. Am I correct in thinking it will be slower to use a JOIN? In Django, I believe the relational tables are created, and I know that I can use a relational table in Rails if I want to. I am wondering why this is the default behavior and if it makes any difference at all.

Thanks

+1  A: 

Rails won't use any joins if you won't tell it to do so.

Let's say you have a User model with has_many :posts:

User.all
# SELECT * FROM `users`

User.all :joins => :posts
# SELECT `users`.* FROM `users` INNER JOIN `posts` ON posts.user_id = users.id

User.all :include => :posts
# SELECT * FROM `users`
# SELECT `posts`.* FROM `posts` WHERE (`posts`.user_id IN (1,2))

If you don't need/want to join then there will be no join.

Tomas Markauskas
+1  A: 

In ActiveRecord (which is the ORM used by default within Rails but not the only one possible) a has_many relationship will typically involve two models and hence two tables. So these models:

class Order < ActiveRecord::Base
  has_many :order_items
end

class OrderItem < ActiveRecord::Base
  belongs_to :order
end

...will reference orders and order_items tables, the latter having a foreign_key order_id reference to its parent order.

Order.find(some_id)

will retrieve a single order. order_items won't be touched unless you reference it explicitly, or add directives into your class definition to require the the association always be navigated.

I'm not sure why you're so concerned about using joins though. With appropriate indexing almost any modern DBMS will be highly efficient: it's what they're designed to do.

Mike Woodhouse
Thanks. I'm not really concerned about it. Just curious. I figured it was doing something that made sense. It just didn't seem to be the way I had learned to do it in school.
Joe Cannatti
+2  A: 

No, by default, a has_many relationship does not use a join to find related rows. Here's a quick command line sessions that show this (I have a debug logger turned on for my script/console).

$ rails has_many_test

$ cd has_many_test

$ ruby script/generate model account

$ ruby script/generate model user account_id:integer

$ rake db:migrate

$ ruby script/console
Loading development environment (Rails 2.3.4)
>> Account.has_many :users
>> a = Account.create
  Account Create (0.4ms)   INSERT INTO "accounts" ("created_at", "updated_at") VALUES('2009-11-28 18:06:50', '2009-11-28 18:06:50')
>> a.users
  User Load (0.3ms)   SELECT * FROM "users" WHERE ("users".account_id = 1)

However, if the has_many relationship defines :through or :include options, the SQL will result in a JOIN, but correctly so.

Ryan McGeary