goldiloader, 只需要正确的Rails 加载量

分享于 

8分钟阅读

GitHub

  繁體 雙語
Just the right amount of Rails eager loading
  • 源代码名称:goldiloader
  • 源代码网址:http://www.github.com/salsify/goldiloader
  • goldiloader源代码文档
  • goldiloader源代码下载
  • Git URL:
    git://www.github.com/salsify/goldiloader.git
    Git Clone代码到本地:
    git clone http://www.github.com/salsify/goldiloader
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/salsify/goldiloader
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    Goldiloader

    Gem VersionBuild StatusCode ClimateCoverage Status

    如果wsrr没有让你考虑即时加载并且它只是在默认情况下完成了"右边"事件,那么这不是很棒? 用Goldiloader它可以 !

    这里分支只支持 4.2 + 和 ruby 2.1 +。 对于旧版本的Rails/ruby,使用 1 -x-stable。

    考虑以下模型:

    classBlog <ActiveRecord::Base has_many :postsendclassPost <ActiveRecord::Base belongs_to :blogend

    下面是一些没有Goldiloader的示例查询:

    > blogs =Blogs.limit(5).to_a# SELECT * FROM blogs LIMIT 5> blogs.each { |blog| blog.posts.to_a }# SELECT * FROM posts WHERE blog_id = 1# SELECT * FROM posts WHERE blog_id = 2# SELECT * FROM posts WHERE blog_id = 3# SELECT * FROM posts WHERE blog_id = 4# SELECT * FROM posts WHERE blog_id = 5

    以下是与Goldiloader相同的查询:

    > blogs =Blogs.limit(5).to_a# SELECT * FROM blogs LIMIT 5> blogs.each { |blog| blog.posts.to_a }# SELECT * FROM posts WHERE blog_id IN (1,2,3,4,5)

    哇它自动在单个数据库查询中为我们的五个博客加载所有的文章,而不指定任何 ! Goldiloader假定你将以统一方式访问从查询加载的所有模型。 第一次遍历任何模型上的关联时,它将立即加载所有模型的关联。 它甚至可以处理关联的任意嵌套。

    阅读更多关于Goldiloader的动机在这个博客文章。

    安装

    将此行添加到你的应用程序的Gemfile中:

    
    gem 'goldiloader'
    
    
    
    

    然后执行:

     
    $ bundle
    
    
    
     

    或者将它的自己安装为:

    
    $ gem install goldiloader
    
    
    
    

    用法

    默认情况下,所有关联在首次访问时都会自动加载,因此希望大多数用例都不需要额外的配置。 注意你仍然可以通过 eager_loadincludes 或者 preload 显式地显式加载负载关联。

    禁用自动加载加载

    你可以使用 auto_include 查询范围方法禁用自动加载:

    Blog.order(:name).auto_include(false)

    这也可以用于禁用关联的自动加载:

    classBlog <ActiveRecord::Base has_many :posts, -> { auto_include(false) }end

    关联选项

    Goldiloader支持ActiveRecord关联的几个选项来定制它的行为。

    fully_load

    有几种关联方法可以在内存模型中执行,或者根据关联在SQL中进行推送。 这包括以下方法:

    • first
    • second
    • third
    • fourth
    • fifth
    • forty_two ( Rails 4.1中的隐藏 Gems 之一)
    • last
    • size
    • ids_reader
    • empty?
    • exists?

    如果我们不再指定立即加载,这可能会导致某些使用模式出现问题:

    > blogs =Blogs.limit(5).to_a# SELECT * FROM blogs LIMIT 5> blogs.each do |blog| 
     if blog.posts.exists? 
     puts blog.posts
     elseputs'No posts'end# SELECT 1 AS one FROM posts WHERE blog_id = 1 LIMIT 1# SELECT * FROM posts WHERE blog_id IN (1,2,3,4,5)

    注意,第一次调用 blog.posts.exists? 是通过SQL执行的,因为 posts 关联还没有加载。 可以使用 fully_load 选项强制ActiveRecord在评估 exists? 等方法时完全加载关联( 并执行任何必要的自动加载):

    classBlog <ActiveRecord::Base has_many :posts, fully_load:trueend

    限制

    Goldiloader利用 ActiveRecord eager加载器,因此它共享一些相同的限制。

    依赖SQL限制的 has_one关联

    你不应该尝试自动加载( 或者常规eager负荷) has_one 关联,它实际上对应于多个记录,并且依赖SQL限制只返回一条记录。 请考虑以下示例:

    classBlog <ActiveRecord::Base has_many :posts has_one :most_recent_post, -> { order(published_at: desc) }, class_name:'Post'end

    使用标准 Rails 延迟加载 most_recent_post 关联加载了如下查询:

    SELECT*FROM posts WHERE blog_id =1ORDER BY published_at DESCLIMIT1

    使用自动加载( 或者常规正加载) 时,most_recent_post 关联会加载一个类似这样的查询:

    SELECT*FROM posts WHERE blog_id IN (1,2,3,4,5) ORDER BY published_at DESC

    注意,不能再使用SQL限制,从而获取每个博客的所有帖子。 这可能会导致严重的性能问题,如果有大量的帖子。

    其他限制

    无法加载与以下任何选项关联的关联:

    • limit
    • offset
    • finder_sql
    • group ( 由于 Rails Bug )
    • from ( 由于 Rails Bug )

    Goldiloader检测与这些选项的关联,并禁用对它们的自动加载。

    插件升级

    来自 0. x, 1.x

    auto_include 关联选项已经被删除,以支持 auto_include 查询范围方法。 指定这里选项的关联必须迁移到使用查询范围方法:

    classBlog <ActiveRecord::Base# Old syntax has_many :posts, auto_include:false# New syntax has_many :posts, -> { auto_include(false) }end

    状态

    使用 MRI。2.2.2.3和 2.4和 JRuby,使用 Rails 4.2.5.0和 5.1测试了这个 gem。

    如果你发现任何问题或者有任何反馈,请告知我们。

    更改日志

    请参阅更改日志

    • fork
    • 创建你的特征分支( git checkout -b my-new-feature )
    • 提交你的更改( git commit -am 'Add some feature' )
    • 推送到分支( git push origin my-new-feature )
    • 创建新的拉请求