Skip to main content
The Kai Way

After Eager Loading

Eager Loading是ActiveRecord的一个数据查询的优化措施,在查询model的时候连同它的关联对象都全查询出来(通过一条包含LEFT OUTER JOIN的SQL语句)。但是在你使用了Eager Loading后,如果还是用一些会触发数据库本身的统计函数的查询方法(如count,average等)的话,那前面的Eager Loading就白费了。下面给出例子:

两个Model,Project和Task,关系是Project has_many Task。

在ProjectController的show中:

@project = Project.find(params[:id], :include => [:articles, :tasks])

这是project/show页面:

<h1><%=h @project.title %></h1> <h2><%=h @project.description %></h2> <p>统计信息:<br/>共有<%= @project.tasks.count %>个<%=link_to '任务', project_tasks_path(@project)%>, 已完成<%= @project.completed_tasks.length %>个任务。 <hr/> <h3>最新未完成的5个任务</h3> <table>   <tr>     <th width="25%">任务名</th>     <th width="75%">任务摘要</th>   </tr>   <% for task in @project.tasks.incompleted %>     <tr>       <td><%= link_to task.name, project_task_path(@project,task) %></td>       <td><%= task.content %></td>     </tr>   <% end %> </table>

来看看log吧:

Project Load Including Associations (0.000595) SELECT projects.id AS t0_r0, projects.title AS t0_r1, projects.description AS t0_r2, projects.created_at AS t0_r3, projects.updated_at AS t0_r4, articles.id AS t1_r0, articles.subject AS t1_r1, articles.summary AS t1_r2, articles.content AS t1_r3, articles.project_id AS t1_r4, articles.created_at AS t1_r5, articles.updated_at AS t1_r6, articles.lock_version AS t1_r7, tasks.id AS t2_r0, tasks.name AS t2_r1, tasks.content AS t2_r2, tasks.completed AS t2_r3, tasks.project_id AS t2_r4, tasks.created_at AS t2_r5, tasks.updated_at AS t2_r6 FROM projects LEFT OUTER JOIN articles ON articles.project_id = projects.id LEFT OUTER JOIN tasks ON tasks.project_id = projects.id WHERE (projects.id = 2) Rendering template within layouts/application Rendering projects/show SQL (0.000255) SELECT count(*) AS count_all FROM tasks WHERE (tasks.project_id = 2)

可以看到在Project的Eager Loading的查询之后可以看到又有一个count()的select查询进行了。那前面的Eager Loading的效果似乎没有了。再试试把count方法调用改为调用length方法,这时就看不到另外的那个count()查询了。

这个可能在写代码的时候不会太留意,不过这对性能的影响还是有些的,如果Eager Loading后不会在调用统计函数就ok了。