Giter Club home page Giter Club logo

lysenko / activerecord-delay_touching Goto Github PK

View Code? Open in Web Editor NEW

This project forked from godaddy/activerecord-delay_touching

0.0 2.0 0.0 28 KB

Batch up your ActiveRecord "touch" operations for better performance. ActiveRecord::Base.delay_touching do ... end. When "end" is reached, all accumulated "touch" calls will be consolidated into as few database round trips as possible.

Home Page: https://rubygems.org/gems/activerecord-delay_touching

License: MIT License

Ruby 100.00%

activerecord-delay_touching's Introduction

Activerecord::DelayTouching

Note: this version requires ActiveRecord 4.2 or higher. To use ActiveRecord 3.2 through 4.1, use the branch https://github.com/godaddy/activerecord-delay_touching/tree/pre-activerecord-4.2.

Batch up your ActiveRecord "touch" operations for better performance.

When you want to invalidate a cache in Rails, you use touch: true. But when you modify a bunch of records that all belong_to the same owning record, that record will be touched N times. It's incredibly slow.

With this gem, all touch operations are consolidated into as few database round-trips as possible. Instead of N touches you get 1 touch.

Installation

Add this line to your application's Gemfile:

gem 'activerecord-delay_touching'

And then execute:

$ bundle

Or install it yourself:

$ gem install activerecord-delay_touching

Usage

The setup:

class Person < ActiveRecord::Base
  has_many :pets
  accepts_nested_attributes_for :pets
end

class Pet < ActiveRecord::Base
  belongs_to :person, touch: true
end

Without delay_touching, this simple update in the controller calls @person.touch N times, where N is the number of pets that were updated via nested attributes. That's N-1 unnecessary round-trips to the database:

class PeopleController < ApplicationController
  def update
    ...
    #
    @person.update(person_params)
    ...
  end
end

# SQL (0.1ms)  UPDATE "people" SET "updated_at" = '2014-07-09 19:48:07.137158' WHERE "people"."id" = 1
# SQL (0.1ms)  UPDATE "people" SET "updated_at" = '2014-07-09 19:48:07.138457' WHERE "people"."id" = 1
# SQL (0.1ms)  UPDATE "people" SET "updated_at" = '2014-07-09 19:48:07.140088' WHERE "people"."id" = 1

With delay_touching, @person is touched only once:

ActiveRecord::Base.delay_touching do
  @person.update(person_params)
end

# SQL (0.1ms)  UPDATE "people" SET "updated_at" = '2014-07-09 19:48:07.140088' WHERE "people"."id" = 1

Consolidates Touches Per Table

In the following example, a person gives his pet to another person. ActiveRecord automatically touches the old person and the new person. With delay_touching, this will only make a single round-trip to the database, setting updated_at for all Person records in a single SQL UPDATE statement. Not a big deal when there are only two touches, but when you're updating records en masse and have a cascade of hundreds touches, it really is a big deal.

class Pet < ActiveRecord::Base
  belongs_to :person, touch: true

  def give(to_person)
    ActiveRecord::Base.delay_touching do
      self.person = to_person
      save! # touches old person and new person in a single SQL UPDATE.
    end
  end
end

Cascading Touches

When delay_touch runs through and touches everything, it captures additional touch calls that might be called as side-effects. (E.g., in after_touch handlers.) Then it makes a second pass, batching up those touches as well.

It keeps doing this until there are no more touches, or until the sun swallows up the earth. Whichever comes first.

Gotchas

Things to note:

  • after_touch callbacks are still fired for every instance, but not until the block is exited. And they won't happen in the same order as they would if you weren't batching up your touches.
  • If you call person1.touch and then person2.touch, and they are two separate instances with the same id, only person1's after_touch handler will be called.

Contributing

  1. Fork it ( https://github.com/godaddy/activerecord-delay_touching/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

activerecord-delay_touching's People

Contributors

athal7 avatar bmorearty avatar krainboltgreene avatar lysenko avatar mjaniszewski-godaddy avatar tjschuck avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.