Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Speeded up eager loading a whole bunch

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1212 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 49d0f0cb66bc7b6d9cf69bd07b168669b3818cee 1 parent 3b9bf64
@dhh dhh authored
View
88 activerecord/lib/active_record/associations.rb
@@ -683,34 +683,42 @@ def find_with_associations(options = {})
schema_abbreviations = generate_schema_abbreviations(reflections)
primary_key_table = generate_primary_key_table(reflections, schema_abbreviations)
- rows = select_all_rows(options, schema_abbreviations, reflections)
- records = extract_and_instantiate_records(schema_abbreviations, rows)
-
- assign_associations_to_records(rows, records, reflections, schema_abbreviations, primary_key_table)
+ rows = select_all_rows(options, schema_abbreviations, reflections)
+ records = { }
+ primary_key = primary_key_table[table_name]
+
+ for row in rows
+ id = row[primary_key]
+ records[id] ||= instantiate(extract_record(schema_abbreviations, table_name, row))
- return records
- end
-
- def assign_associations_to_records(rows, records, reflections, schema_abbreviations, primary_key_table)
- records.each do |record|
reflections.each do |reflection|
+ next unless row[primary_key_table[reflection.table_name]]
+
case reflection.macro
when :has_many, :has_and_belongs_to_many
- record.send(reflection.name).target =
- extract_association_for_record(record, schema_abbreviations, primary_key_table, rows, reflection)
+ records[id].send(reflection.name)
+ records[id].instance_variable_get("@#{reflection.name}").target.push(
+ reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.table_name, row))
+ )
when :has_one, :belongs_to
- record.send(
- "set_#{reflection.name}_target",
- extract_association_for_record(record, schema_abbreviations, primary_key_table, rows, reflection).first
+ records[id].send(
+ "#{reflection.name}=",
+ reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.table_name, row))
)
end
end
end
+
+ return records.values
end
-
+
+ def reflect_on_included_associations(associations)
+ [ associations ].flatten.collect { |association| reflect_on_association(association) }
+ end
+
def generate_schema_abbreviations(reflections)
- schema = [ [ table_name, columns.collect { |c| c.name } ] ]
- schema += reflections.collect { |r| [ r.klass.table_name, r.klass.columns.collect { |c| c.name } ] }
+ schema = [ [ table_name, column_names ] ]
+ schema += reflections.collect { |r| [ r.table_name, r.klass.column_names ] }
schema_abbreviations = {}
schema.each_with_index do |table_and_columns, i|
@@ -736,9 +744,14 @@ def generate_primary_key_table(reflections, schema_abbreviations)
end
- def construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections)
- habtm_associations = reflections.find_all { |r| r.macro == :has_and_belongs_to_many }
+ def select_all_rows(options, schema_abbreviations, reflections)
+ connection.select_all(
+ construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections),
+ "#{name} Load Including Associations"
+ )
+ end
+ def construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections)
sql = "SELECT #{column_aliases(schema_abbreviations)} FROM #{table_name} "
sql << reflections.collect { |reflection| association_join(reflection) }.to_s
sql << "#{options[:joins]} " if options[:joins]
@@ -775,39 +788,14 @@ def association_join(reflection)
end
- def extract_and_instantiate_records(schema_abbreviations, rows)
- rows.collect { |row| instantiate(extract_record(schema_abbreviations, table_name, row)) }.uniq
- end
-
- def extract_association_for_record(record, schema_abbreviations, primary_key_table, rows, reflection)
- association = rows.collect do |row|
- if row[primary_key_table[table_name]].to_s == record.id.to_s && !row[primary_key_table[reflection.klass.table_name]].nil?
- reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.klass.table_name, row))
- end
- end
-
- return association.uniq.compact
- end
-
def extract_record(schema_abbreviations, table_name, row)
- row.inject({}) do |record, pair|
- prefix, column_name = schema_abbreviations[pair.first]
- record[column_name] = pair.last if prefix == table_name
- record
+ record = {}
+ row.each do |column, value|
+ prefix, column_name = schema_abbreviations[column]
+ record[column_name] = value if prefix == table_name
end
- end
-
-
- def reflect_on_included_associations(associations)
- [ associations ].flatten.collect { |association| reflect_on_association(association) }
- end
-
- def select_all_rows(options, schema_abbreviations, reflections)
- connection.select_all(
- construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections),
- "#{name} Load Including Associations"
- )
- end
+ return record
+ end
end
end
end
View
4 activerecord/lib/active_record/associations/association_proxy.rb
@@ -32,6 +32,10 @@ def loaded?
@loaded
end
+ def target
+ @target
+ end
+
def target=(t)
@target = t
@loaded = true
View
6 activerecord/lib/active_record/base.rb
@@ -618,6 +618,10 @@ def columns
def columns_hash
@columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
end
+
+ def column_names
+ @column_names ||= columns_hash.keys
+ end
# Returns an array of columns objects where the primary id, all columns ending in "_id" or "_count",
# and columns used for single table inheritance has been removed.
@@ -640,7 +644,7 @@ def column_methods_hash
# Resets all the cached information about columns, which will cause they to be reloaded on the next request.
def reset_column_information
- @columns = @columns_hash = @content_columns = @dynamic_methods_hash = nil
+ @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = nil
end
def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
View
6 activerecord/lib/active_record/reflection.rb
@@ -114,7 +114,11 @@ def name_to_class_name(name)
# Holds all the meta-data about an association as it was specified in the Active Record class.
class AssociationReflection < MacroReflection #:nodoc:
def klass
- active_record.send(:compute_type, (name_to_class_name(name.id2name)))
+ @klass ||= active_record.send(:compute_type, (name_to_class_name(name.id2name)))
+ end
+
+ def table_name
+ @table_name ||= klass.table_name
end
private
Please sign in to comment.
Something went wrong with that request. Please try again.