`
hideto
  • 浏览: 2666295 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ActiveRecord的lazy loading与eager loading

    博客分类:
  • Ruby
阅读更多
看来大家还对ActiveRecord的lazy loading和eager loading不是很清楚

ActiveRecord默认是lazy loading的,而加上:include选项后可以指定eager loading一些字段
:include  - specify second-order associations that should be eager loaded when the collection is loaded.

看例子:
Post.find(:all, :include => :comments)
  # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ...


我再把active_recordassociations.rb的源代码翻出来给大家看看:
1,base.rb
  def with_scope(method_scoping = {}, action = :merge, &block)
    method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)

    # Dup first and second level of hash (method and params).
    method_scoping = method_scoping.inject({}) do |hash, (method, params)|
      hash[method] = (params == true) ? params : params.dup
      hash
    end

    method_scoping.assert_valid_keys([ :find, :create ])

    if f = method_scoping[:find]
      f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly, :lock ])
      f[:readonly] = true if !f[:joins].blank? && !f.has_key?(:readonly)
    end

    # Merge scopings
    if action == :merge && current_scoped_methods
      method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)|
        case hash[method]
          when Hash
            if method == :find
              (hash[method].keys + params.keys).uniq.each do |key|
                merge = hash[method][key] && params[key] # merge if both scopes have the same key
                if key == :conditions && merge
                  hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ")
                elsif key == :include && merge
                  hash[method][key] = merge_includes(hash[method][key], params[key]).uniq
                else
                  hash[method][key] = hash[method][key] || params[key]
                end
              end
            else
              hash[method] = params.merge(hash[method])
            end
          else
            hash[method] = params
        end
        hash
      end
    end

    self.scoped_methods << method_scoping

    begin
      yield
    ensure
      self.scoped_methods.pop
    end
  end

  def find_every(options)
    records = scoped?(:find, :include) || options[:include] ?
      find_with_associations(options) : 
      find_by_sql(construct_finder_sql(options))

    records.each { |record| record.readonly! } if options[:readonly]

    records
  end


2,associations.rb
module ActiveRecord
  module Associations
    module ClassMethods
      private
        def find_with_associations(options = {})
          catch :invalid_query do
            join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins])
            rows = select_all_rows(options, join_dependency)
            return join_dependency.instantiate(rows)
          end
          []
        end

        def select_all_rows(options, join_dependency)
          connection.select_all(
            construct_finder_sql_with_included_associations(options, join_dependency),
            "#{name} Load Including Associations"
          )
        end

        def construct_finder_sql_with_included_associations(options, join_dependency)
          scope = scope(:find)
          sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || table_name} "
          sql << join_dependency.join_associations.collect{|join| join.association_join }.join
 
          add_joins!(sql, options, scope)
          add_conditions!(sql, options[:conditions], scope)
          add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])

          sql << "GROUP BY #{options[:group]} " if options[:group]
 
          add_order!(sql, options[:order], scope)
          add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
          add_lock!(sql, options, scope)
 
          return sanitize_sql(sql)
        end

        class JoinDependency

          class JoinAssociation < JoinBase
            def association_join
              join = case reflection.macro
                when :has_and_belongs_to_many
                  " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [
                     table_alias_for(options[:join_table], aliased_join_table_name),
                     aliased_join_table_name,
                     options[:foreign_key] || reflection.active_record.to_s.classify.foreign_key,
                     parent.aliased_table_name, reflection.active_record.primary_key] +
                  " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [
                     table_name_and_alias, aliased_table_name, klass.primary_key,
                     aliased_join_table_name, options[:association_foreign_key] || klass.table_name.classify.foreign_key
                     ]
                when :has_many, :has_one
                    ...
                when :belongs_to
                    ...
                else
                    ...
              join
            end
          end

        end

调用流程是这样的:
ActiveRecord.find* -> with_scope -> find_every -> find_with_associations -> select_all_rows -> construct_finder_sql_with_included_associations -> association_join
如果提供:include选项,则调用find_with_associations,即eager loading,否则调用find_by_sql,为lazy loading
最后我们看到JoinAssociation的association_join方法使用LEFT OUTER JOIN来做关联查询,做eager loading

一切都弄清楚了吧?

BTW:对于open source项目,遇到问题时看看source code是很好的solution
分享到:
评论

相关推荐

    ActiveRecord简单实例_activerecord.zip

    在Ruby on Rails框架中,ActiveRecord是一个至关重要的组件,它负责模型(Model)与数据库之间的交互。本实例将深入探讨ActiveRecord的基本用法,帮助理解如何在实际开发中有效地运用这个强大的工具。 首先,让我们...

    Pro ActiveRecord Databases with Ruby and Rails.pdf

    ### ActiveRecord在Ruby与Rails中的高级应用 #### 一、引言 《Pro ActiveRecord Databases with Ruby and Rails》这本书深入探讨了如何使用ActiveRecord框架来高效地处理Ruby on Rails中的数据库操作。本书由Kevin ...

    Castle.ActiveRecord (.NET FrameWork 2.0)

    Castle.ActiveRecord For .NET FrameWork 2.0 如果你想使用Castle.ActiveRecord,但又不想使用.NET Framework 3.0/3.5/4.0或更高版本,那么这个就是你所需要的,For .NET FrameWork 2.0,我整理了好久,自己从官方...

    NHibernate中文教程+activerecord

    Castle ActiveRecord是NHibernate ActiveRecord实现的一个版本,提供了额外的功能和方便性。它是一个AOP(面向切面编程)框架,能够自动管理对象的生命周期,包括事务、验证和持久化。 9. **最佳实践** 在实际...

    Python-ActiveRecord类似Django的查询嵌套式加载和美化reprforSQLAlchemy

    默认情况下,SQLAlchemy使用懒加载(Lazy Loading),即只有在需要访问关联对象时才执行额外的SQL查询。为了减少数据库交互次数,我们可以使用`joinedload`或`subqueryload`来实现嵌套式加载: ```python user_...

    Castle ActiveRecord 手册

    此外,延迟加载(Lazy Loading)可以按需加载关联对象,避免一次性加载大量数据。 8. **事件处理**:Castle ActiveRecord支持生命周期事件,如`Saving`、`Saved`、`Deleting`和`Deleted`,允许你在对象保存或删除...

    Castle ActiveRecord 2.0

    它也提供了事务管理、懒加载(Lazy Loading)、级联操作和事件处理等功能,使得开发更加高效和灵活。 **2. 特性支持** - **属性映射**:通过 `ActiveRecord` 和 `Column` 特性,可以直接在类和字段级别定义数据库...

    简单Castle.ActiveRecord.Generator

    ActiveRecord是面向对象持久化的一个设计模式,将对象与数据库表之间的映射关系直接定义在对象模型上,使得数据库操作更加直观和便捷。 首先,让我们深入理解 Castle ActiveRecord 框架。Castle项目是一个开源的...

    scala-activerecord-specs_2.9.2-0.2.3.zip

    "scala-activerecord-specs_2.9.2-0.2.3.zip" 这个标题表明我们正在处理一个与Scala Activerecord相关的软件包,具体是版本为0.2.3的规格测试部分,适用于Scala 2.9.2。"specs"通常指的是软件的规范或测试套件,意味...

    ActiveRecord 升级NHibernate到3.3.0GA

    将ActiveRecord中的NHibernate升级到3.3.0GA,排除编译的bug问题,保留ActiveRecord的完整功能,【Castle.ActiveRecord 升级NHibernate到3.4.0GA】的功能不完整!

    [IronRuby] C# 4.0调用ActiveRecord

    从提供的文件信息中,我们可以得知这篇博文主要讨论的是如何使用C# 4.0调用IronRuby中的ActiveRecord功能。不过由于博文链接和部分详细内容无法提供,知识点将基于文件信息部分和公共知识构建。 知识点一:IronRuby...

    C# Castle.ActiveRecord CS源码示例教程.zip

    ActiveRecord 是一种设计模式,源自 Ruby on Rails,它将业务对象与数据库记录关联起来,使得开发者可以直接操作对象,而无需编写大量的 SQL 语句。Castle.ActiveRecord 将这种理念带到了 .NET 平台,通过注解或者...

    ar_lazy_preload:ActiveRecord模型的延迟加载关联

    您唯一需要更改的是使用#lazy_preload而不是#includes #eager_load , #includes #eager_load或#preload 快。 查看( TASK=bench和TASK=memory ) 非常适合GraphQL 。 定义要在顶级解析器中加载的关联列表,并让gem...

    Castle.ActiveRecord 升级NHibernate到3.4.0GA

    Castle.ActiveRecord官方已经停止更新了,官方最高支持到NHibernate 3.1.0.4000,这个版本还有不少问题(例如:[NH-2213] - CLONE -Wrong parameters order in IQuery with SetParameterList and Filter)。...

    lazy_find:简化了ActiveRecord中的first,last,take方法

    Simplified the first,last,take methods in ActiveRecord.So instead of using where and first, you can directly use first. 安装 将此行添加到您的应用程序的Gemfile中: gem 'lazy_find' 然后执行: $ ...

    Apress Pro ActiveRecord Databases with Ruby and Rails.pdf

    - 尽量避免N+1查询问题,利用预加载(Eager Loading)减少不必要的数据库交互。 - 合理使用索引,提高查询性能。 3. **数据安全性**: - 对敏感数据进行加密存储,防止数据泄露。 - 使用参数化查询防止SQL注入...

    MyBatisPlus的ActiveRecord实现CRUD示例代码

    通过实体类与数据库表的映射,开发者可以直接对对象进行CRUD操作,而无需关注底层的SQL语句。这不仅降低了代码的复杂性,也使得代码更易于维护。在实际项目中,结合MyBatisPlus的其他特性,如条件构造器、关联查询等...

    userstamp, 这个 Rails 插件扩展ActiveRecord.zip

    userstamp, 这个 Rails 插件扩展ActiveRecord Userstamp插件( v-2.0 )概述Userstamp插件扩展了 ActiveRecord::Base,以添加对'创建者','更新程序'和'deleter'属性的自动更新。 它是基于 ActiveRecord::Timesta

    C# Castle.ActiveRecord Winform 源码示例教程

    Castle.ActiveRecord 的资料很多,但是WINFORM的没几个,于此我专门写了个例子献给初学Castle.ActiveRecord的童鞋们,希望这篇文档能够帮到你们。这个例子使用的是ACCESS数据库,从单表,一对多,多对多,数据绑定,...

    Java敏捷持久层-ROR-ActiveRecord持久层框架的Java实现

    ActiveRecord是一种对象关系映射(ORM)模式,起源于Ruby on Rails框架,它的核心思想是将数据库表与面向对象的类绑定,每个表对应一个类,表中的记录对应类的实例。这样,开发者可以通过操作对象的方式来间接操作...

Global site tag (gtag.js) - Google Analytics