What's New in Edge Rails: Partial Updates

Posted by ryan
at 3:45 PM on Tuesday, April 01, 2008

In lock-step with the recent dirty objects functionality comes the ability of ActiveRecord models to perform partial updates – which only saves the attributes that have been modified on updates.

For instance:

1
2
3
4
5
6
7
8
9
10
article = Article.find(:first)
article.title  #=> "Title"
article.subject  #=> "Edge Rails"

# Update one of the attributes
article.title = "New Title"

# And only that updated attribute is persisted to the db
article.save
  #=>  "UPDATE articles SET title = 'New Title' WHERE id = 1"

Note: Your updated_at/on magic fields will only be set if there are unsaved attributes that need persisting. If there are no changed attributes for the object being persisted then there won’t be any SQL updates made.

To disable this functionality, set partial_updates = false for each model you wish to not take advantage of partial updates. To disable this system-wide add this line to your environment.rb or, better yet, in a config/initializer:


ActiveRecord::Base.partial_updates = false

Note: There’s currently a config/initializers/new_rails_defaults.rb file that has this setting, so edit that file if you have it.

tags: ruby, rubyonrails

Comments

Leave a response

  1. Trevor TurkApril 01, 2008 @ 04:22 PM

    Would enabling this functionality have performance benefits?

  2. Eric AndersonApril 01, 2008 @ 04:35 PM

    I would think any performance benefits would be small maybe even unnoticeable. I would guess only less network traffic. Even that is only really a factor if you are saving large blocks of data in your database (binary data, large text areas, etc.). I guess if the database wasn’t very smart it might also save a small amount of database time updating data that hasn’t changed and/or updating indexes that haven’t changed. But I would think most databases would only do updates if the new data was different than the old data. Just a guess.

    For me the big advantage is less noise on my log files. I don’t have to read through fields that haven’t changed to understand what has changed. If the field in in the update then it changed. Makes the queries submitted much more like the queries I would hand code. Only of course I don’t have to actually hand code them. :)

  3. RyanApril 01, 2008 @ 04:50 PM

    Don’t forget that there will also be less potential for write-conflicts. Simultaneous writes to the same record on different attributes will no longer overwrite the one before it and cause data inconsistencies.

  4. Michael SchuerigApril 01, 2008 @ 05:47 PM

    Ryan, I don’t think that having fewer write-conflicts is a practical benefit of partial updates. Such conflicts should never go unnoticed and unhandled. Fortunately, Rails has been supporting optimistic looking for ages using the lock_version attribute.

  5. SebastianApril 01, 2008 @ 05:50 PM

    It looks very nice, I will try it in my next application.

  6. DHHApril 01, 2008 @ 07:21 PM

    The reason the setting is turned on in config/initializers/new_rails_defaults.rb is such that all new applications will have it on by default, but older applications get a chance to ensure whether they’re compatible before this setting becomes default on for 3.0.

  7. Diego Pires PlentzApril 01, 2008 @ 10:09 PM

    Learning good things from hibernate :)

  8. jasonApril 02, 2008 @ 12:30 AM

    performance benefits from this change could be huge or could be imperceptible – it depends on what you are updating. Saving yourself unnecessary updates on indexed columns in large, high contention tables can be a life saver. if you are saving updates to un-indexed fields, you probably won’t see much difference.

  9. Dan MangesApril 02, 2008 @ 02:00 AM

    There’s risk with this that 2 partial updates end up creating an invalid record, right? Is it recommended to only use partial updates with locking?

  10. Adam GreeneApril 02, 2008 @ 11:17 AM

    Bingo jason! that is exactly why I’m looking forward to this.

    I have a few tables that are heavily indexed, read a lot, but also have a fair amount of updating. Partial updates could potentially really help out in this regard. I’m curious how much this feature will improve updating objects that contain large serialized columns and that are pushed to a db not on the local box. benchmarking time!

  11. Eric AndersonApril 02, 2008 @ 07:01 PM

    Jason,

    Would it really help in the indexes even though no updates are being made? I would think the database would be smart enough to compare the two for equality before doing the actual update. Be interesting to know which database are smart and do the right thing and which ones blindly update the column and indexes regardless of the fact that nothing actually changes.

  12. Steve IannopolloApril 03, 2008 @ 12:41 PM

    Eric,

    I think what Jason meant is that the app won’t try to hit the database, which would save a trip to the database and the time spent doing so.

    My question is: Does it take most databases any longer to update the whole record (all columns) versus just updating 1 or 2 columns?

    Either way, this is a sweet addition to the framework.

  13. FrankApril 03, 2008 @ 04:48 PM

    Nice trick, but what about efficiency in middle and huge database?

  14. MortenApril 08, 2008 @ 04:04 AM

    Late to the party, but for me this is god sent. All our cumbersome lifecycle and audit management code can now be beautifully refactored out into observers.