Merge pull request #33223 from rails/homogeneous-allocation

Speed up homogeneous AR lists / reduce allocations
This commit is contained in:
Aaron Patterson 2018-06-26 14:16:06 -07:00 committed by GitHub
commit 316513177c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 2 deletions

View File

@ -344,6 +344,28 @@ module ActiveRecord
self
end
##
# Initializer used for instantiating objects that have been read from the
# database. +attributes+ should be an attributes object, and unlike the
# `initialize` method, no assignment calls are made per attribute.
#
# :nodoc:
def init_from_db(attributes)
init_internals
@new_record = false
@attributes = attributes
self.class.define_attribute_methods
yield self if block_given?
_run_find_callbacks
_run_initialize_callbacks
self
end
##
# :method: clone
# Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.

View File

@ -67,8 +67,18 @@ module ActiveRecord
# how this "single-table" inheritance mapping is implemented.
def instantiate(attributes, column_types = {}, &block)
klass = discriminate_class_for_record(attributes)
instantiate_instance_of(klass, attributes, column_types, &block)
end
# Given a class, an attributes hash, +instantiate_instance_of+ returns a
# new instance of the class. Accepts only keys as strings.
#
# This is private, don't call it. :)
#
# :nodoc:
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
klass.allocate.init_from_db(attributes, &block)
end
# Updates an object (or multiple objects) and saves it to the database, if validations pass.

View File

@ -49,7 +49,12 @@ module ActiveRecord
}
message_bus.instrument("instantiation.active_record", payload) do
result_set.map { |record| instantiate(record, column_types, &block) }
if result_set.includes_column?(inheritance_column)
result_set.map { |record| instantiate(record, column_types, &block) }
else
# Instantiate a homogeneous set
result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
end
end
end

View File

@ -43,6 +43,11 @@ module ActiveRecord
@column_types = column_types
end
# Returns true if this result set includes the column named +name+
def includes_column?(name)
@columns.include? name
end
# Returns the number of elements in the rows array.
def length
@rows.length

View File

@ -12,6 +12,11 @@ module ActiveRecord
])
end
test "includes_column?" do
assert result.includes_column?("col_1")
assert_not result.includes_column?("foo")
end
test "length" do
assert_equal 3, result.length
end