`
qiezi
  • 浏览: 497691 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

ActiveRecord 查询优化

    博客分类:
  • Ruby
阅读更多
ActiveRecord使用很方便,只需要声明映射关系,就可以方便地获取各个关联对象,而且是延迟加载。有时候这种关系延迟加载可能会严重影响性能,比如下面这个例子:
class User < ActiveRecord::Base
end

class Post < ActiveRecord::Base
  has_many :replies
end

class Reply < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
end

我们在查询某一个帖子的同时,希望取到所有回复以及回复者。
@post = Post.find(params[:id])

<%= @post.body %>
<hr />
<% @post.replies.each do |reply| -%>
  <%= reply.body %><br />Post by: <%= reply.user.name %><hr />
<% end -%>

如果你查看日志,就会发现一大堆的查询,类似于:
SELECT * FROM users WHERE id = xx limit 1

这个对性能的影响还是很严重的,所以需要改进查询,在查询出reply的同时把user也查询出来。把它修改为:
@post = Post.find(params[:id], :include => {:replies => :user})

这次所有查询都在一条语句中进行了,不过某些情况下你可以会发现它反而会降低查询效率,原因在于本来只有1条的post记录也被扩展到多条了,这时候还是分开查询为好:
@post = Post.find(params[:id])
@replies = @post.replies.find(:all, :include => :user)

是的,这次总共只有2条语句,一般情况下效率都会提升许多。


使用find with :include可以提高效率,但尽量不要对一对多关系使用。如果只是一对一关系,那么即便是很多层的关联,效率也还不错。比如这样:
Street.find(1, :include => {:city => {:province => {:country => :continent}}})


有时我们还是要查询一些一对多关系,这时候也可以采用其它一些技巧,例如下面这个查询:
Comment.find(1, :include => {:user => {:replies => :post}})

我把它理解为:查询某一评论(comment),同时查出发表这一评论的用户发表过的回复帖子,以及这些帖子所回复的主题。当然这种查询可能是不合理的,只是想探讨一下如何优化这种查询。

由于数据库查询的效率往往比服务器处理要低,而且服务器很容易扩展而数据库集群则难以部署,所以我们还是要尽量减少查询次数,同时不增加查询数据量。

这里我的想法是把它分成2次查询:
@comments = Comment.find(:all, :include => :user)
user_ids = [0].concat(@comments.map(&:user).map(&:id))
replies = Replies.find(:all, :conditions => ["user_id in (?)", user_ids], :include => :post)
@user_replies = {}
replies.each {|r| @user_replies[r.user_id] ||= []; @user_replies[r.user_id] << r}

然后直接使用就可以了,在要显示某用户的回复及这些回复的主题时,只要把user.id作为key从@user_replies里提取。使用[0].concat是防止可能构造出一个空数组,查询时会生成一个非法SQL语句,这里也假设0是一个无效的ID值。

我曾经在一些查询中使用这个做法,结果数据库查询时间缩短了近10倍,整个action的处理效率也因此提高了4倍。
分享到:
评论
4 楼 eltonto 2007-04-06  
不必要的查询还是不要查,楼主做的对
3 楼 together 2006-11-29  
引用
我在测试时发现影响还是比较大的,特别是数据库和WEB服务器不在同一台机器上时。

我有过感受。如果web服务器和数据库不在同一台机器上,确实性能会有影响。但如果在同一个内网的话,问题应该不大。我们公司遇到过的一个比较明显的例子是,有一个PHP的应用,oci连接oracle,运行得非常慢,检查了很久也没找出原因在哪里,最后把数据库连接字符串中的hostname改为IP地址,运行就飞快了。可能是域名解析方面不稳定,耗时过多。
用ror来操作oracle,应该也有可能会遇到这样的情况。当然我说的不太沾边,只是一个特例。
2 楼 qiezi 2006-11-29  
我在测试时发现影响还是比较大的,特别是数据库和WEB服务器不在同一台机器上时。

大批量数据导入导出很难有通用的解决方案,很可能不适合在rails中做。统计分页这些我倾向于在数据库中解决,简单的分页自己实现也比较容易。
1 楼 together 2006-11-29  
不错的介绍。不过多查询几条sql语句,对效率的影响应该不是很大。影响最大的应该是大数据量下的分页、统计,以及大批量数据导入、导出等等
现在就是事情太多,沉不下心来认真学习。等有空的时候,一定把ROR好好用一下。

相关推荐

    Rails Best Practices

    8. **数据库设计**:合理设计数据库表结构,使用外键和索引来优化查询性能。考虑数据库的扩展性和一致性,例如使用JOINs来合并数据,而不是在应用层处理。 9. **安全**:遵循RESTful设计,利用Rails的安全特性,如...

    Ruby-OccamsRecord缺少ActiveRecord的高效查询API

    这对于需要优化查询性能的开发者来说是一个有利的工具,但对那些不熟悉SQL的人来说可能学习曲线会比较陡峭。 在压缩包"occams-record-master"中,可能包含了Occam's Record库的源代码,包括README文件、示例代码和...

    Pro ActiveRecord Databases with Ruby and Rails.pdf

    - 如何优化查询性能。 - 如何利用ActiveRecord处理大量数据。 - 如何在复杂的应用场景下保持代码的可维护性。 #### 七、总结 《Pro ActiveRecord Databases with Ruby and Rails》是一本针对中级到高级Ruby on ...

    NHibernate中文教程+activerecord

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

    Ruby-一个轻量级和数据库级Ruby库用于将任何ActiveRecord查询转换为分析哈希以备任何图表库使用

    综合这些信息,我们可以推断出这个Ruby库是一个专注于数据库查询和数据转换的工具,它帮助开发者将ActiveRecord查询结果转化为分析哈希,便于在各种图表库中进行数据可视化。对于Ruby on Rails开发者来说,这可以极...

    ASP源码—实现ActiveRecord数据查询更新 v1.0.zip

    在"ASP源码—实现ActiveRecord数据查询更新 v1.0.zip"中,我们可以推测这是一个实现了ActiveRecord概念的ASP库或框架,允许开发者更便捷地进行数据库查询和更新操作。以下是一些关于ASP和ActiveRecord模式的核心知识...

    简单Castle.ActiveRecord.Generator

    3. **数据库操作方法**:这些方法包括`Save()`(用于创建或更新记录)、`Delete()`(删除记录)、`Find()`或`Load()`(查询和加载记录)等。这些方法由 Castle ActiveRecord 提供,使得开发者无需编写SQL即可执行...

    Ruby-marginalia添加评论至ActiveRecord的SQL查询

    总之,`Ruby-marginalia`是提升ActiveRecord应用开发效率和可维护性的强大工具,通过在SQL查询中添加注释,它提供了宝贵的上下文信息,使开发者能够更有效地管理和优化数据库交互。在进行性能优化或者调试时,`...

    Ruby-SearchCop为ActiveRecord提供类似搜索引擎的全文查询支持

    然而,标准的ActiveRecord查询并不总是满足复杂的全文搜索需求。这时,`SearchCop`应运而生,它是一个强大的插件,旨在为ActiveRecord添加类似于搜索引擎的全文查询功能。 **SearchCop的核心特性** 1. **灵活的...

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

    Java 敏捷持久层技术是现代软件开发中的一个重要组成部分,它简化了数据库操作,使得...虽然ActiveRecord在小到中型项目中表现出色,但对于大数据量、高并发的应用场景,可能需要更优化的解决方案,如MyBatis或JPA。

    Castle ActiveRecord快速入门指南、ActiveRecord帮助文档

    - 调整 NHibernate 的配置参数以优化查询效率。 8. **帮助文档** - 提供的 `.chm` 文件是 Castle ActiveRecord 的官方帮助文档,包含了详细的功能说明、示例代码和故障排查指南,是学习和解决问题的重要资源。 ...

    Ruby-pgeyeballs一个Rubygem能提供由ActiveRecord创建关于SQL查询的详细信息

    Ruby-pg-eyeballs是一个专门针对Ruby on Rails框架中ActiveRecord组件的工具,它能够帮助开发者深入理解并分析由ActiveRecord生成的SQL查询。在Ruby开发过程中,尤其是在处理复杂数据库交互时,这个gem显得尤为有用...

    castle ActiveRecord 源代码

    4. **查询API**:Castle ActiveRecord提供了强大的查询API,包括简单的属性查询、复杂的HQL(Hibernate Query Language)以及LINQ支持。这使得开发者可以方便地进行数据筛选、聚合、排序等操作。 5. **性能优化**:...

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

    总结,这个主题主要展示了如何在SQLAlchemy中实现类似于Active Record的编程风格,包括如何定义模型、使用Session查询数据、实现嵌套加载以优化性能,以及通过重写`__repr__`方法和使用Mixins来提升代码的可读性和可...

    wdi_10_rails_query_optimization

    ActiveRecord 查询优化嘘,别告诉任何人……但是你在过去 9 周中构建的所有 Rails 应用程序的数据库性能可能都非常糟糕! 为什么? 因为 Rails 使编写导致N+1 查询的代码变得非常容易。 N+1 是一个性能问题,在页面...

    Apress Pro ActiveRecord Databases with Ruby and Rails.pdf

    - **自定义查询**:虽然ActiveRecord提供了强大的查询功能,但在某些情况下可能需要编写原生SQL查询。 - **性能调优**:随着应用规模的增长,性能问题逐渐显现,需要采取措施进行优化。 #### 七、结论 《Pro ...

    Ruby-SchemaPlus提供增强和扩展ActiveRecord的集合

    5. **表分区** - 对于大数据场景,`SchemaPlus`支持表分区,优化存储和查询效率。 6. **序列化** - 提供了更强大的序列化机制,可以序列化更复杂的数据结构。 7. **数据库兼容性** - 支持多种数据库系统,如MySQL...

    助推器

    1. **ActiveRecord查询优化**:避免N+1查询,使用`includes`预加载关联数据,或者使用`pluck`和`select`只获取必要的列。 2. **缓存策略**:利用Rails的页面、片段和动作缓存,或者使用Redis、Memcached等外部缓存...

Global site tag (gtag.js) - Google Analytics