N + 1 問題是當需要從資料庫中找資料時,應該要一次抓完所需資料,但卻使用逐筆撈資料的方式處理,可能會導致大量的資料庫查詢,這種情況通常在 Rails 中的 Active Record 查詢中出現,尤其是大量使用關聯性時,白話來說在同一個地方本來可以一次抓例如5個資料,卻分成5次慢慢抓這樣
# 在 controller 中 抓所有文章及其評論
@posts = Post.all
# 在 view 中跑過所有文章並輸出評論數
<% @posts.each do |post| %>
<p><%= post.title %></p>
<p>評論數:<%= post.comments.count %></p>
<% end %>
上述程式碼中,我們首先抓取了所有文章,然後在 view 中遍歷每篇文章以顯示評論數。但是,每次調用 post.comments.count 都會觸發一個額外的資料庫查詢,這就造成了 N + 1 問題,因為我們執行了 N 次(文章數量)的附加查詢
includes 和 eager_load 方法
,可以在查詢主模型時先預載關聯模型的資料,而減少額外的查詢
# 使用 includes 預加載關聯模型的評論數據
@posts = Post.includes(:comments)
# 或者使用 eager_load
@posts = Post.eager_load(:comments)
使用 joins 方法
來聯接主模型和關聯模型,然後通過 select 方法選擇所需的字串,減少不必要的數據擷取
@posts = Post.joins(:comments).select('posts.*, COUNT(comments.id) AS comments_count').group('posts.id')
手動緩存某些數據,以減少重複查詢
@posts = Post.all
@comment_counts = Comment.group(:post_id).count
有一些 gem 套件(例如 bullet 和 rack-mini-profiler)可以幫忙檢測並解決 N + 1 問題,以幫助優化查詢
N + 1 問題是在 Ruby on Rails 開發中常見的性能問題
,但可以通過使用內建方法和技巧來解決。選擇所需的方法,並根據專案的複雜性和數據量來優化查詢,了解和解決 N + 1 問題是開發高效率 Rails 應用程式的重要技巧
明天預計來介紹什麼是 gem ,我們明天見!