모형과 관련된 등급이 두 층을 초과할 때includes 설정하기

13999 단어 Rails

계기.


모델의 연관 등급이 많은 경우 잘 설정되지 않아서includes 조사해봤어요

결론


길기 때문에 결론을 먼저 쓴다User has_many Project has_many Task has_many Tagincludes는 다음과 같다.
<%= render User.includes(projects: [tasks: [:tags, :category]]).all %>

점프대를 준비하다

rails g scaffold user name
rails g model project name user:belongs_to
rails g model task name project:belongs_to category:belongs_to
rails g model tag name task:belongs_to
rails g model category name
rake db:migrate
class User < ActiveRecord::Base
  has_many :projects
end

class Project < ActiveRecord::Base
  belongs_to :user
  has_many :tasks
end

class Task < ActiveRecord::Base
  belongs_to :project
  belongs_to :category
  has_many :tags
end

class Tag < ActiveRecord::Base
  belongs_to :task
end

class Category < ActiveRecord::Base
end
users/index.html.erb
<ul>
  <%= render User.all %>
</ul>
users/_user.html.erb
<li>
  <%= user.name %>
  <ul>
    <%= render user.projects %>
  </ul>
</li>
projects/_project.html.erb
<li>
  <%= project.name %>
  <ul>
    <%= render project.tasks %>
  </ul>
</li>
tasks/_task.html.erb
<li>
  <%= task.name %><br>
  Category: <%= task.category.try(:name) %><br>
  Tags: <%= task.tags.collect(&:name).join(', ') %>
</li>
  • 아래 링크 가져오기 참조bullet
  • Rails 라이브러리 소개: N+1 문제를 감지하는 "bullet"
  • 상황 확인

  • 적절한 데이터 입력
  • rails s 서버 부팅

  • 방문http://localhost:3000/users할 때 console에 메시지를 표시하고 화면에 다음과 같은 경보가 나타나야 한다
  • user: gyo
    localhost:3000http://localhost:3000/users
    N+1 Query detected
      User => [:projects]
      Add to your finder: :include => [:projects]
    N+1 Query method call stack
      /Users/gyo/test/multi_level_include/app/views/users/_user.html.erb:4:in `_app_views_users__user_html_erb___436787215809601570_70334830513800'
      /Users/gyo/test/multi_level_include/app/views/users/index.html.erb:2:in `_app_views_users_index_html_erb___1780560768163965305_70334830660840'
    user: gyo
    localhost:3000http://localhost:3000/users
    N+1 Query detected
      Project => [:tasks]
      Add to your finder: :include => [:tasks]
    N+1 Query method call stack
      /Users/gyo/test/multi_level_include/app/views/projects/_project.html.erb:4:in `_app_views_projects__project_html_erb__760140089216941139_70334830446180'
      /Users/gyo/test/multi_level_include/app/views/users/_user.html.erb:4:in `_app_views_users__user_html_erb___436787215809601570_70334830513800'
      /Users/gyo/test/multi_level_include/app/views/users/index.html.erb:2:in `_app_views_users_index_html_erb___1780560768163965305_70334830660840'
    user: gyo
    localhost:3000http://localhost:3000/users
    N+1 Query detected
      Task => [:category]
      Add to your finder: :include => [:category]
    N+1 Query method call stack
      /Users/gyo/test/multi_level_include/app/views/tasks/_task.html.erb:3:in `_app_views_tasks__task_html_erb__3289746241671965391_70334829873900'
      /Users/gyo/test/multi_level_include/app/views/projects/_project.html.erb:4:in `_app_views_projects__project_html_erb__760140089216941139_70334830446180'
      /Users/gyo/test/multi_level_include/app/views/users/_user.html.erb:4:in `_app_views_users__user_html_erb___436787215809601570_70334830513800'
      /Users/gyo/test/multi_level_include/app/views/users/index.html.erb:2:in `_app_views_users_index_html_erb___1780560768163965305_70334830660840'
    user: gyo
    localhost:3000http://localhost:3000/users
    N+1 Query detected
      Task => [:tags]
      Add to your finder: :include => [:tags]
    N+1 Query method call stack
      /Users/gyo/test/multi_level_include/app/views/tasks/_task.html.erb:4:in `_app_views_tasks__task_html_erb__3289746241671965391_70334829873900'
      /Users/gyo/test/multi_level_include/app/views/projects/_project.html.erb:4:in `_app_views_projects__project_html_erb__760140089216941139_70334830446180'
      /Users/gyo/test/multi_level_include/app/views/users/_user.html.erb:4:in `_app_views_users__user_html_erb___436787215809601570_70334830513800'
      /Users/gyo/test/multi_level_include/app/views/users/index.html.erb:2:in `_app_views_users_index_html_erb___1780560768163965305_70334830660840'
    



  • 아쉬운 SQL
  • Started GET "/users" for 127.0.0.1 at 2014-07-04 18:57:50 +0900
    Processing by UsersController#index as HTML
      User Load (0.1ms)  SELECT "users".* FROM "users"
      Project Load (0.2ms)  SELECT "projects".* FROM "projects"  WHERE "projects"."user_id" = ?  [["user_id", 1]]
      Task Load (0.2ms)  SELECT "tasks".* FROM "tasks"  WHERE "tasks"."project_id" = ?  [["project_id", 2]]
      Category Load (0.1ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 6]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 11]]
      Category Load (0.1ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 12]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 28]]
      Rendered tasks/_task.html.erb (10.5ms)
      Task Load (0.1ms)  SELECT "tasks".* FROM "tasks"  WHERE "tasks"."project_id" = ?  [["project_id", 3]]
      Category Load (0.3ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 5]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 38]]
      Rendered tasks/_task.html.erb (3.2ms)
      Task Load (0.1ms)  SELECT "tasks".* FROM "tasks"  WHERE "tasks"."project_id" = ?  [["project_id", 4]]
      Category Load (0.1ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 11]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 7]]
      CACHE (0.0ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 11]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 9]]
      Category Load (0.1ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 4]]
      Tag Load (0.0ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 37]]
      Rendered tasks/_task.html.erb (8.2ms)
      Rendered projects/_project.html.erb (30.9ms)
      Project Load (0.1ms)  SELECT "projects".* FROM "projects"  WHERE "projects"."user_id" = ?  [["user_id", 2]]
      Task Load (0.1ms)  SELECT "tasks".* FROM "tasks"  WHERE "tasks"."project_id" = ?  [["project_id", 8]]
    ......
      Task Load (0.1ms)  SELECT "tasks".* FROM "tasks"  WHERE "tasks"."project_id" = ?  [["project_id", 6]]
      CACHE (0.1ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 10]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 3]]
      CACHE (0.0ms)  SELECT  "categories".* FROM "categories"  WHERE "categories"."id" = ? LIMIT 1  [["id", 5]]
      Tag Load (0.1ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" = ?  [["task_id", 23]]
      Rendered tasks/_task.html.erb (7.3ms)
      Rendered projects/_project.html.erb (11.2ms)
      Rendered users/_user.html.erb (203.6ms)
      Rendered users/index.html.erb within layouts/application (205.4ms)
    

    includes로 대응하기


    users/index.html.erb
    <ul>
      <%= render User.includes(projects: [tasks: [:tags, :category]]).all %>
    </ul>
    

    대응 SQL

    Started GET "/users" for 127.0.0.1 at 2014-07-04 19:01:48 +0900
    Processing by UsersController#index as HTML
      User Load (0.1ms)  SELECT "users".* FROM "users"
      Project Load (0.4ms)  SELECT "projects".* FROM "projects"  WHERE "projects"."user_id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
      Task Load (0.3ms)  SELECT "tasks".* FROM "tasks"  WHERE "tasks"."project_id" IN (2, 3, 4, 8, 10, 12, 13, 16, 19, 11, 14, 17, 5, 9, 15, 7, 18, 20, 1, 6)
      Tag Load (0.7ms)  SELECT "tags".* FROM "tags"  WHERE "tags"."task_id" IN (11, 28, 38, 7, 9, 37, 27, 3, 23, 15, 34, 5, 17, 18, 20, 31, 13, 25, 4, 14, 22, 24, 10, 19, 1, 26, 30, 16, 35, 29, 32, 2, 33, 6, 12, 21, 36, 39, 40, 8)
      Category Load (0.2ms)  SELECT "categories".* FROM "categories"  WHERE "categories"."id" IN (6, 12, 5, 11, 4, 2, 10, 16, 17, 13, 18, 3, 14, 8, 9, 7, 15)
      Rendered tasks/_task.html.erb (0.6ms)
      Rendered tasks/_task.html.erb (0.4ms)
      Rendered tasks/_task.html.erb (1.0ms)
      Rendered projects/_project.html.erb (4.1ms)
      Rendered tasks/_task.html.erb (2.4ms)
      Rendered tasks/_task.html.erb (1.5ms)
      Rendered collection (0.0ms)
      Rendered projects/_project.html.erb (6.5ms)
      Rendered tasks/_task.html.erb (4.1ms)
      Rendered tasks/_task.html.erb (0.9ms)
      Rendered tasks/_task.html.erb (1.9ms)
      Rendered projects/_project.html.erb (10.1ms)
      Rendered collection (0.0ms)
      Rendered collection (0.0ms)
      Rendered tasks/_task.html.erb (1.1ms)
      Rendered tasks/_task.html.erb (0.6ms)
      Rendered projects/_project.html.erb (3.2ms)
      Rendered collection (0.0ms)
      Rendered collection (0.0ms)
      Rendered tasks/_task.html.erb (0.4ms)
      Rendered tasks/_task.html.erb (0.7ms)
      Rendered collection (0.0ms)
      Rendered projects/_project.html.erb (2.6ms)
      Rendered tasks/_task.html.erb (0.7ms)
      Rendered tasks/_task.html.erb (0.6ms)
      Rendered tasks/_task.html.erb (0.3ms)
      Rendered projects/_project.html.erb (4.1ms)
      Rendered collection (0.0ms)
      Rendered tasks/_task.html.erb (0.6ms)
      Rendered projects/_project.html.erb (1.6ms)
      Rendered users/_user.html.erb (38.8ms)
      Rendered users/index.html.erb within layouts/application (59.0ms)
    Completed 200 OK in 64ms (Views: 61.5ms | ActiveRecord: 1.7ms)
    

    실행 효율 비교

    // 対応前
    Rendered users/index.html.erb within layouts/application (205.4ms)
    // 対応後
    Rendered users/index.html.erb within layouts/application (59.0ms)
    

    좋은 웹페이지 즐겨찾기