activerecord-delay_touching icon indicating copy to clipboard operation
activerecord-delay_touching copied to clipboard

Add Rails 5 support

Open Kenneth-KT opened this issue 5 years ago • 2 comments

This PR adds Rails 5.0 support to the activerecord-delay_touching gem. This PR does not break Rails 4.0 compatibility. Rspec has passed against both latest Rails version 5.2.1 and 4.2.9.

One drawback of this implementation is it does not respect time in xxx.touch(time: time), it will only be filled with current time.

Kenneth-KT avatar Nov 20 '18 06:11 Kenneth-KT

Hi @Kenneth-KT. Our general stance has been that this library will not need to support Rails 5, due to changes being made in Rails core that have similar goals. See https://github.com/godaddy/activerecord-delay_touching/issues/13#issuecomment-285949342.

Is there something that this library does that's missing in the Rails 5 solution, which would make it beneficial for us to support Rails 5?

mtuckergh avatar Nov 20 '18 18:11 mtuckergh

Hi @Kenneth-KT. Our general stance has been that this library will not need to support Rails 5, due to changes being made in Rails core that have similar goals. See #13 (comment).

Is there something that this library does that's missing in the Rails 5 solution, which would make it beneficial for us to support Rails 5?

@mtuckergd Yes, this library does have features that ActiveRecord 5.0 does not provide.

  1. It only touches the same record once across multiple transactions.
  2. It aggregates touch calls of multiple records within the same table in one SQL.

Consider the following code sample:

person = Person.create!
pets = 100.times.collect { Pet.create!(person: person) }
pets.each_slice(10) do |part_of_pets|
  ActiveRecord::Base.transaction do
    part_of_pets.each { |x| x.touch_later }
  end
end

This code sample generates 110 queries:

Query #1: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #2: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #3: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #4: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #5: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #6: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #7: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #8: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #9: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #10: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #11: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #12: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #13: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #14: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #15: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #16: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #17: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #18: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #19: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #20: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #21: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #22: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #23: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #24: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #25: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #26: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #27: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #28: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #29: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #30: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #31: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #32: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #33: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #34: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #35: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #36: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #37: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #38: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #39: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #40: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #41: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #42: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #43: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #44: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #45: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #46: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #47: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #48: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #49: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #50: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #51: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #52: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #53: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #54: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #55: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #56: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #57: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #58: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #59: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #60: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #61: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #62: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #63: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #64: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #65: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #66: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #67: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #68: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #69: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #70: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #71: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #72: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #73: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #74: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #75: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #76: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #77: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #78: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #79: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #80: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #81: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #82: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #83: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #84: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #85: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #86: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #87: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #88: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #89: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #90: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #91: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #92: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #93: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #94: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #95: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #96: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #97: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #98: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #99: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #100: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #101: UPDATE "people" SET "updated_at" = ? WHERE "people"."id" = ?
Query #102: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #103: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #104: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #105: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #106: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #107: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #108: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #109: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?
Query #110: UPDATE "pets" SET "updated_at" = ? WHERE "pets"."id" = ?

You can see that the same People record has got updated 10 times because touch_later could not work across multiple transactions. Also, there are 100 updates to pets because it cannot aggregate multiple record touches within the same table into one single SQL.

If we wrap the code with delay_touching, as in this code sample:

person = Person.create!
pets = 100.times.collect { Pet.create!(person: person) }
ActiveRecord::Base.delay_touching do
  pets.each_slice(10) do |part_of_pets|
    ActiveRecord::Base.transaction do
      part_of_pets.each { |x| x.touch_later }
    end
  end
end

It only generates 2 queries:

Query #1: UPDATE "pets" SET "updated_at" = '2018-11-21 13:38:51.589657' WHERE "pets"."id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Query #2: UPDATE "people" SET "updated_at" = '2018-11-21 13:38:51.599752' WHERE "people"."id" = ?

We are running a production system that needs to support bulk importing and updating 100k+ record on daily basis, all those queries saved dramatically improved performance of our system.

Kenneth-KT avatar Nov 21 '18 14:11 Kenneth-KT