美文网首页ruby on rails
(1)includes解决N+1查询问题

(1)includes解决N+1查询问题

作者: suhuanzhen | 来源:发表于2016-11-27 00:58 被阅读0次

    参考资料:http://guides.ruby-china.org/active_record_querying.html#%E6%8C%89%E9%9C%80%E5%8A%A0%E8%BD%BD%E5%85%B3%E8%81%94

    资料案例

    N+1查询问题

    假设有如下的代码,获取10个客户对象,并把客户的邮编打印出来

    clients = Client.limit(10)
     
    clients.each do |client|
      puts client.address.postcode
    end
    

    商品的代码看起来很好,但问题在于查询的总次数。上述代码总共会执行1(获取10个客户记录)+10(分别获取10个客户的地址)= 11次查询

    N+1查询的解决办法

    我们使用includes方法可以在取出10个客户记录的同时把这些记录关联的客户地址一次性取出来,这样我们在访问客户地址时就不用再去执行查询语句了,因为第一次已经把所需数据全部查询出来了。
    使用includes的代码:

    clients = Client.includes(:address).limit(10)
     
    clients.each do |client|
      puts client.address.postcode
    end
    

    和前面的 11 次查询不同,上述代码只会执行 2 次查询:

    SELECT * FROM clients LIMIT 10
    SELECT addresses.* FROM addresses
    WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))

    构造案例

    创建项目

    rails _4.2.2_ new active_record_first -d=mysql
    

    修改Gemfile文件,把gem源替换为source 'https://gems.ruby-china.org',把gem 'mysql2'替换为gem 'mysql2', '~> 0.3.18'
    把database.yml文件里面的数据库密码设置为本地mysql数据库的密码

    cd  active_record_first
    
    bundle install
    
    rake  db:create
    

    构造数据

    需要两张表,先创建两张表的迁移文件

    rails g migration CreateProducts
    
    rails g migration CreateProductSecondTags
    
    商品表 products
    image.png image.png
    商品二级标签表 product_second_tags
    image.png image.png

    我们数据表不需要默认生成的id属性,所以添加上id: false
    我们使用rails默认的数据类型,定义就用t.string、t.integer的形式。
    我们需要sql语句去定义类型时,定义就用t.column后面跟上sql数据类型定义。
    数据表中的外键经常用于查询,所以我们一般都会加上索引。
    凡是ID字段,都用CHAR(36)的类型。

    添加字段
    rails g migration AddSecondTagIdToProducts
    

    我们往products表添加一个新的字段TagID,不过我们在迁移文件里面写的时候迁移文件名是AddSecondTagIdToProducts,而不是AddSecondTagIDToProducts

    填充数据表数据
    image.png image.png
    添加模型文件
    image.png image.png

    product模型需要访问它关联的数据表记录,所以数据关联belongs_to需要写在product模型文件。而我们目前不需要通过product_second_tag.products的访问方式,所以product_second_tag不需要添加has_many数据关联。

    添加路由文件
    image.png
    添加控制器文件
    image.png

    Rails c模型下调试

    注意:在rails c模型下,无论是代码发生变更,或者我们在navicat里面插入新的数据,都需要重新进入rails c控制台才能生效。

    字段大小写

    我们在find_by中根据字段进行查找时,字段不区分大小写
    我们访问查询结果的字段时只有id(ID)属性不区分大小写,其他字段区分大小写

    image.png image.png
    N+1查询问题

    每次each,都执行一次sql查询,所以下面执行6次each,造成6次查询(n次查询)


    image.png

    使用includes的话,在得到products记录的时候一次性把products关联的二级标签记录都得到了。不管有没有each里面的访问都是两条sql查询

    image.png

    视图文件下进行调试

    遗留问题,为什么会出现CACHE,我们就算在配置文件关闭缓存,添加如下代码config.action_controller.perform_caching = false还是会有CACHE。

    可以看到,查询ProductSecondTag执行多条SQL语句


    image.png image.png

    使用includes之后,就算不访问关联表,也执行2次查询

    我们只有操作数据时才会执行查询语句,如下不进行访问就没有查询语句


    image.png
    image.png

    我们访问数据的长度(就算不在视图中<%= %>进行显示),这时就执行了查询语句。


    image.png
    image.png

    我们在第一个语句并不执行sql语句。后面第一次使用数据时执行两条sql语句获取到所有数据了。所有第二次、第三次。。。第n次使用数据时都不再执行sql查询语句。


    image.png
    image.png
    image.png

    使用Git做版本控制

    进入项目根目录

    .../active_record_first#  git init
    Initialized empty Git repository in /home/**********/active_record_first/.git/
    
    git add -A
    git commit -m "ActiveRecordFirst"
    

    然后创建一个git仓库

    image.png

    提交

    git push -u https://github.com/xiaohuacc/active_record.git master
    

    然后我们就可以在git仓库看到我们提交的代码了


    image.png

    在本地有时

    取消提交(慎用)

    我们有时从远程仓库拷贝代码到本地之后,在本地提交了自己的多次修改,但是需求变动之后这些修改不需要了。我们可以取消这些修改,使用命令git reset --hard加上提交版本号;不过要注意我们使用该命令回退到指定A版本之后push到远程仓库,A版本后面的commit历史就没了----(无法通过commit历史看到A版本之后的修改提交了)。一般这个命令要慎用,而且只用于回到自己最近一次本地的commit版本(该commit未push到远程仓库)。

    我们在首次提交之后,又在视图文件添加了一下代码。现在我们不要这些首次提交后的修改又很难一个个找到变动的地方改回来,于是使用
    首次提交,使用git log命令查看

    commit bf2bd5a242d64564cd85383e17caa1af9ce786c8
    Author: ***
    Date:   Sun Nov 27 14:59:05 2016 +0800
        ActiveRecordFirst
    
    

    然后又做了一下修改并提交了

    git add .
    git commit -m "测试git取消修改功能"
    [master 77f455d] 测试git取消修改功能
     2 files changed, 4 insertions(+), 4 deletions(-)
    
    git log
    commit 77f455d78967518c9db4f49812d739d3d0285224
    Author: ***
    Date:   Sun Nov 27 15:11:53 2016 +0800
        测试git取消修改功能
    
    commit bf2bd5a242d64564cd85383e17caa1af9ce786c8
    Author: ***
    Date:   Sun Nov 27 14:59:05 2016 +0800
        ActiveRecordFirst
    

    我们回到首次提交时的状态,去掉第二次提交的代码修改

    git reset --hard bf2bd5a242d64564cd85383e17caa1af9ce786c8
    HEAD is now at bf2bd5a ActiveRecordFirst
    

    然后回到IDE点击YES重新加载项目代码


    image.png

    然后我们git log可以看到没有第二次提交的log,这也意味着我们想要回到第二次的提交也是不行了。

    commit bf2bd5a242d64564cd85383e17caa1af9ce786c8
    Author: ***
    Date:   Sun Nov 27 14:59:05 2016 +0800
        ActiveRecordFirst
    
    

    相关文章

      网友评论

        本文标题:(1)includes解决N+1查询问题

        本文链接:https://www.haomeiwen.com/subject/jwggpttx.html