美文网首页
数据库高级使用

数据库高级使用

作者: yaya_pangdun | 来源:发表于2016-06-12 14:25 被阅读69次

    1、在Model使用sql语句

    before_destroy :clean_data
    
    def clean_data
      teacher_id = self.id
      sql = "delete * from train_teacher where nurse_info_id = #{teacher_id}"
      #这个方法是私有方法,必须在Model中使用
      ActiveRecord::Base.connection.exec(sql)
    end
    

    2、数据库的优化
    一. N+1 queries 问题

    # model
    class User < ActieRecord::Base
      has_one :car
    end
    
    class Car < ActiveRecord::Base
      belongs_to :user
    end
    
    # your controller
    def index
      @users = User.page(params[:page])
    end
    
    # view
    <% @users.each do |user| %>
     <%= user.car.name %>
    <% end %>
    

    当我们在View中使用user.car.name的时候,会导致N+1 queries(多次查询数据库),假设User有10笔,这程式会产生出11笔Queries,一笔是查
    User,另外10笔是一笔一笔去查Car,严重拖慢效能。

    SELECT * FROM `users` LIMIT 10 OFFSET 0
    SELECT * FROM `cars` WHERE (`cars`.`user_id` = 1)
    SELECT * FROM `cars` WHERE (`cars`.`user_id` = 2)
    SELECT * FROM `cars` WHERE (`cars`.`user_id` = 3)
    ...
    ...
    ...
    SELECT * FROM `cars` WHERE (`cars`.`user_id` = 10)
    

    解决方法,加上includes:

    # your controller
    def index
      @users = User.includes(:car).page(params[:page])
    end
    

    如此SQL query就只有两个,只用一个就查出所有Cars资料。

    SELECT * FROM `users` LIMIT 10 OFFSET 0
    SELECT * FROM `cars` WHERE (`cars`.`user_id` IN('1','2','3','4','5','6','7','8',' 9','10'))
    

    二. 索引
    需要加索引的列:

    • 外键(Foreign Key)
    • 需要排序的列
    • 被查询的列
    • 会被group的列

    三. 使用select
    ActiveRecord会将数据库中的所有列取出来,浪费内存。

    #只取出id,name,description这些字段
    Event.select(:id, :name, :description).limit(10)
    

    四. 使用计数器
    在ActiveRecord中经常要计算has_many的Model有多少关联的数据。

    <% @topics.each do |topic| %>
      主题:<%= topic.subject %>
      回复数:<%= topic.posts.size %>
    <% end %>
    

    这个时候会产生很多SQL查询。

    SELECT * FROM `posts` LIMIT 5 OFFSET 0
    SELECT count(*) AS count_all FROM `posts` WHERE (`posts`.topic_id = 1 )
    SELECT count(*) AS count_all FROM `posts` WHERE (`posts`.topic_id = 2 )
    SELECT count(*) AS count_all FROM `posts` WHERE (`posts`.topic_id = 3 )
    SELECT count(*) AS count_all FROM `posts` WHERE (`posts`.topic_id = 4 )
    SELECT count(*) AS count_all FROM `posts` WHERE (`posts`.topic_id = 5 )
    

    使用counter cache会把这个数字存进数据库。必须在Topic这个Model增加一个字段。

    rails g migration add_posts_count_to_topic
    

    编辑Migration文件

    class AddPostsCountToTopic < ActiveRecord::Migration
      def change  
        add_column :topics, :posts_count, :integer, :default => 0
        
        Topic.pluck(:id).each do |i|
          Topic.reset_counters(i, :posts) # 全部重算一次
        end
      end
    end
    

    编辑Model文件,加入counter_cache => true

    class Topic < ActiveRecord::Base
      has_many :posts
    end
    
    class Posts < ActiveRecord::Base
      belongs_to :topic, :counter_cache => true
    end
    

    这样topic.posts.size会自动转化为topic.posts_count
    五. 查询优化
    如果要查出所有的数据,不要用all,all会一次把所有的数据取到内存中去。

    
    

    六. 逆正规化

    相关文章

      网友评论

          本文标题:数据库高级使用

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