krn
krn

Reputation: 6815

Ruby on Rails ActiveRecord efficiency

This code should update the entire table by applying a filter to its "name" values:

entries = select('id, name').all
entries.each do |entry|
  puts entry.id
  update(entry.id, { :name => sanitize(entry.name) })
end

I am pretty new to Ruby on Rails and found it interesting, that my selection query is split into the single row selections:

SELECT `entries`.* FROM `entries` WHERE (`entries`.`id` = 1) LIMIT 1
SELECT `entries`.* FROM `entries` WHERE (`entries`.`id` = 2) LIMIT 1
SELECT `entries`.* FROM `entries` WHERE (`entries`.`id` = 3) LIMIT 1
...

As I understand, it's a kind of optimization, provided by Rails - to select a row only when it's needed (every cycle) and not the all entries at once.

However, is it really more efficient in this case? I mean, if I have 1000 records in my database table - is it better to make 1000 queries than a single one? If not, how can I force Rails to select more than one row per query?

Another question is: not all rows are updated by this query. Does Rails ignore the update query, if the provided values are the same which already exist (in other words, if entry.name == sanitize(entry.name))?

Upvotes: 1

Views: 653

Answers (2)

DanSingerman
DanSingerman

Reputation: 36502

ActiveRecord is an abstraction layer, but when doing certain operations (especially those involving large datasets) it is useful to know what is happening underneath the abstraction layer.

This is pretty much true for all abstractions. (see Joel Spolsky's classic article on leaky abstractions: http://www.joelonsoftware.com/articles/LeakyAbstractions.html )

To deal with the case in point here, Rails provides the update_all method

Upvotes: 2

Ariejan
Ariejan

Reputation: 11069

Entry.find_each do |entry|
  #...
end

That fetches all entries (100 per query) and exposes each entry for your pleasure.

If attributes are not changed, Rails will not perform an UPDATE query.

Upvotes: 1

Related Questions