rails数据库查询 N + 1 查询的解决办法

schema.rb

ActiveRecord::Schema.define(version: 20150203032005) do

  create_table "addresses", force: true do |t|
    t.integer  "client_id"
    t.string   "street"
    t.string   "postcode"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "clients", force: true do |t|
    t.string   "name"
    t.string   "gender"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "infos", force: true do |t|
    t.integer  "address_id"
    t.string   "history"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

end

client.rb

class Client < ActiveRecord::Base
  has_one :address
end

address.rb

class Address < ActiveRecord::Base
  belongs_to :client
  has_many :infos
end

info.rb

class Address < ActiveRecord::Base
  belongs_to :client
  has_many :infos
end

Client.all

  Client Load (0.4ms)  SELECT "clients".* FROM "clients"
 => #<ActiveRecord::Relation [#<Client id: 1, name: "wei", gender: "1", created_at: "2015-02-03 02:12:36", updated_at: "2015-02-03 02:12:36">, #<Client id: 2, name: "yan", gender: "1", created_at: "2015-02-03 02:48:11", updated_at: "2015-02-03 02:48:11">]>

Address.all

SELECT "addresses".* FROM "addresses"
 => #<ActiveRecord::Relation [#<Address id: 1, client_id: 1, street: "huanyuan", postcode: "123456", created_at: "2015-02-03 02:13:45", updated_at: "2015-02-03 02:13:45">, #<Address id: 2, client_id: 2, street: "huayuan", postcode: "23456", created_at: "2015-02-03 02:50:12", updated_at: "2015-02-03 02:50:12">]>

Info.all

SELECT "infos".* FROM "infos"
 => #<ActiveRecord::Relation [#<Info id: 1, address_id: 1, history: "1110", created_at: "2015-02-03 03:25:34", updated_at: "2015-02-03 03:25:34">,
 #<Info id: 2, address_id: 1, history: "1111", created_at: "2015-02-03 03:26:16", updated_at: "2015-02-03 03:26:16">,
#<Info id: 3, address_id: 1, history: "1112", created_at: "2015-02-03 03:26:21", updated_at: "2015-02-03 03:26:21">,
#<Info id: 4, address_id: 2, history: "2110", created_at: "2015-02-03 03:26:32", updated_at: "2015-02-03 03:26:32">,
#<Info id: 5, address_id: 2, history: "2111", created_at: "2015-02-03 03:26:34", updated_at: "2015-02-03 03:26:34">,
 #<Info id: 6, address_id: 2, history: "2112", created_at: "2015-02-03 03:26:37", updated_at: "2015-02-03 03:26:37">,
#<Info id: 7, address_id: 2, history: "2113", created_at: "2015-02-03 03:26:39", updated_at: "2015-02-03 03:26:39">]>

  

N + 1 查询的解决办法

clients = Client.limit(2)

clients.each do |client|
  puts client.address.postcode
end

生成的sql语句为:

 SELECT "clients".* FROM "clients"
 => #<ActiveRecord::Relation
[#<Client id: 1, name: "wei", gender: "1", created_at: "2015-02-03 02:12:36", updated_at: "2015-02-03 02:12:36">,
 #<Client id: 2, name: "yan", gender: "1", created_at: "2015-02-03 02:48:11", updated_at: "2015-02-03 02:48:11">]> 

clients = Client.includes(:address).limit(2)

clients.each do |client|
  puts client.address.postcode
end

生成的sql语句为:

 Client Load (0.5ms)  SELECT  "clients".* FROM "clients"  LIMIT 2
  Address Load (0.4ms)  SELECT "addresses".* FROM "addresses"  WHERE "addresses"."client_id" IN (1, 2)
 => #<ActiveRecord::Relation [#<Client id: 1, name: "wei", gender: "1", created_at: "2015-02-03 02:12:36", updated_at: "2015-02-03 02:12:36">,
#<Client id: 2, name: "yan", gender: "1", created_at: "2015-02-03 02:48:11", updated_at: "2015-02-03 02:48:11">]> 

按需加载多个关联

clients = Client.all
clients.each do |client|
    puts client.address.infos.first.history
end

生成的sql语句:

Address Load (0.3ms)  SELECT  "addresses".* FROM "addresses"  WHERE "addresses"."client_id" = ? LIMIT 1  [["client_id", 1]]
  Info Load (0.3ms)  SELECT  "infos".* FROM "infos"  WHERE "infos"."address_id" = ?  ORDER BY "infos"."id" ASC LIMIT 1  [["address_id", 1]]
1110
  Address Load (0.1ms)  SELECT  "addresses".* FROM "addresses"  WHERE "addresses"."client_id" = ? LIMIT 1  [["client_id", 2]]
  Info Load (0.1ms)  SELECT  "infos".* FROM "infos"  WHERE "infos"."address_id" = ?  ORDER BY "infos"."id" ASC LIMIT 1  [["address_id", 2]]
2110
 => [#<Client id: 1, name: "wei", gender: "1", created_at: "2015-02-03 02:12:36", updated_at: "2015-02-03 02:12:36">, #<Client id: 2, name: "yan", gender: "1", created_at: "2015-02-03 02:48:11", updated_at: "2015-02-03 02:48:11">]

Client和Address是has_one关系, Address和info是has_many关系, 想要一次性加载资源使client可以通过address获取info, 使用下面语句:

clients = Client.includes(address: :infos)

生成的sql语句:

 Client Load (0.4ms)  SELECT "clients".* FROM "clients"
  Address Load (0.5ms)  SELECT "addresses".* FROM "addresses"  WHERE "addresses"."client_id" IN (1, 2)
  Info Load (0.3ms)  SELECT "infos".* FROM "infos"  WHERE "infos"."address_id" IN (1, 2)
 => #<ActiveRecord::Relation [#<Client id: 1, name: "wei", gender: "1", created_at: "2015-02-03 02:12:36", updated_at: "2015-02-03 02:12:36">, #<Client id: 2, name: "yan", gender: "1", created_at: "2015-02-03 02:48:11", updated_at: "2015-02-03 02:48:11">]>

  

clients.each do |c|
    puts c.address.infos.first.history
end

输出:

1110
2110

时间: 2024-07-30 17:50:07

rails数据库查询 N + 1 查询的解决办法的相关文章

mysql数据库死锁的产生原因及解决办法

这篇文章主要介绍了mysql数据库锁的产生原因及解决办法,需要的朋友可以参考下 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.加锁是实现数据库并 发控制的一个非常重要的技术.在实际应用中经常会遇到的与锁相关的异常情况,当两个事务需要一组有冲突的锁,而不能将事务继续下去的话,就会出现死锁,严 重影响应用的正常执行. 在数据库中有两种基本的锁类型

mysql中RAND()随便查询记录效率问题和解决办法分享

在我们做开发的中效率一直是个问题,特别是对于很多大数据量操作,今天我们碰到一个要随机查询数据,一开始我们可能想到最简单的order by rand() 来操作但效率不敢恭维啊 最近由于需要大概研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1. 有两个方法可以达成以上效果. 1.新建一个表,里面存着 -5 至 5 之间的数.再利用order

hive命令查询数据不显示表头解决办法

在hive命令行中查询数据如下: 表头未显示出来 解决办法: 修改hive安装包conf/hive-site.xml配置文件: <property> <name>hive.cli.print.header</name> <value>true</value> <description>Whether to print the names of the columns in query output.</description&g

使用union all查询时字段不匹配解决办法

小问题,可能新手碰到也会被书上的定义限定思维,一时反应不过来. 定义: UNION 或UNION ALL 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SELECT 语句中的列的顺序必须相同. 场景: 当两个select的结果集个别字段有差别时需要UNION 或UNION ALL 合并. 解决办法: 某个结果集少字段可以用空值或固定值代替,使用别名达到列名一致要求. 如 要合并s

SQL SERVER 数据库被标记为&ldquo;可疑&rdquo;的解决办法

问题背景: 日常对Sql Server 2005关系数据库进行操作时,有时对数据库(如:Sharepoint网站配置数据库名Sharepoint_Config)进行些不正常操作如数据库在读写时而无故停止数据库,从而导致Sql Server 2005数据库不正常中断,当再次打开数据库时会发现某些数据库会被标记为"可疑"(suspect),即在数据库名旁加上了黄色的惊叹号,这时数据库就不能再被打开了,但数据库的结构及数据内容都还是存在的. 解决方法: 当数据库发生这种操作故障时,可以按如下

L SERVER 数据库被标记为“可疑”的解决办法

问题背景: 日常对Sql Server 2005关系数据库进行操作时,有时对数据库(如:Sharepoint网站配置数据库名Sharepoint_Config)进行些不正常操作如数据库在读写时而无故停止数据库,从而导致Sql Server 2005数据库不正常中断,当再次打开数据库时会发现某些数据库会被标记为“可疑”(suspect),即在数据库名旁加上了黄色的惊叹号,这时数据库就不能再被打开了,但数据库的结构及数据内容都还是存在的. 解决方法: 当数据库发生这种操作故障时,可以按如下操作步骤可

Sql Server 2005/2008数据库被标记为“可疑”的解决办法

日常对Sql Server 2005关系数据库进行操作时,有时对数据库(如:Sharepoint网站配置数据库名Sharepoint_Config)进行些不正常操作如数据库在读写时而无故停止数据库,从而导致Sql Server 2005数据库不正常中断,当再次打开数据库时会发现某些数据库会被标记为"可疑"(suspect),即在数据库名旁加上了黄色的惊叹号,这时数据库就不能再被打开了,但数据库的结构及数据内容都还是存在的. 解决方法: 当数据库发生这种操作故障时,按如下操作步骤可解决此

Sql Server 2008 数据库附加失败提示9004错误解决办法

附加数据库 对于 服务器“WSS_Content”失败.  (Microsoft.SqlServer.Smo)执行 Transact-SQL 语句或批处理时发生了异常. (Microsoft.SqlServer.ConnectionInfo)处理数据库 'WSS_Content' 的日志时出错.如果可能,请从备份还原.如果没有可用备份,可能需要重新生成日志. 无法打开新数据库 'WSS_Content'.CREATE DATABASE 中止. (Microsoft SQL Server,错误:

MYSQL---远程连接mysql数据库提示:ERROR 1130的解决办法

出现这种情况是因为mysql服务器出于安全考虑,默认只允许本地登录数据库服务器. 解决办法: 将远程服务器上的mysql数据库中的user表中root用户所对应的Host字段"127.0.0.1"改为"%"即可. mysql> use mysql mysql> update user set Host="%" where Host="127.0.0.1"; mysql> flush privileges; m

wamp中修改后mysq数据库l闪退无法登陆解决办法

WampServer安装后密码是空的, 修改一般有三种方式: 一是通过phpMyAdmin直接修改: 二是使用WAMP的MySql控制台修改. 三是重置密码 第一种: 1.在phpMyAdmin界面中点击[用户],将用户概况中的所有用户名为[root] 用户的密码都改为[要修改的密码]. 修改是点击[编辑权限],设置密码即可. 2.在目录wamp\apps下找到phpmyadmin文件夹下的[config.inc.php]文件, 修改[$cfg['Servers'][$i]['password'