數(shù)據(jù)庫高級使用

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、數(shù)據(jù)庫的優(yōu)化
一. 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 %>

當(dāng)我們在View中使用user.car.name的時候,會導(dǎo)致N+1 queries(多次查詢數(shù)據(jù)庫),假設(shè)User有10筆,這程式會產(chǎn)生出11筆Queries,一筆是查
User,另外10筆是一筆一筆去查Car,嚴(yán)重拖慢效能。

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會將數(shù)據(jù)庫中的所有列取出來,浪費內(nèi)存。

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

四. 使用計數(shù)器
在ActiveRecord中經(jīng)常要計算has_many的Model有多少關(guān)聯(lián)的數(shù)據(jù)。

<% @topics.each do |topic| %>
  主題:<%= topic.subject %>
  回復(fù)數(shù):<%= topic.posts.size %>
<% end %>

這個時候會產(chǎn)生很多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會把這個數(shù)字存進(jìn)數(shù)據(jù)庫。必須在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會自動轉(zhuǎn)化為topic.posts_count
五. 查詢優(yōu)化
如果要查出所有的數(shù)據(jù),不要用all,all會一次把所有的數(shù)據(jù)取到內(nèi)存中去。


六. 逆正規(guī)化

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容