【Rails】N+1 문제에 대한 정리
N+1 문제란?
N + 1 문제는 데이터베이스에서 데이터를 검색 할 때 많은 양의 SQL이 발행되어 성능이 저하되는 문제입니다.
N+1 문제의 구체적인 예
rails는 all 및 find 메소드를 사용하여 데이터베이스에서 데이터를 검색합니다.
터미널의 로그를 보면 실제로는 아래와 같이 그때마다 SQL이 실행되고 있습니다.
SQLProduct Load (2.7ms) SELECT `products`.* FROM `products`
users 테이블
id
이름
1
야마다
2
아라이
3
다나카
4
키타가와
products 테이블
id
제품
group_id
1
카레
2
2
물고기
1
3
불고기
3
4
사시미
1
"사용자 하나는 여러 제품을 가진 관계이므로 사용자 모델에 has_many 메소드를 정의하고 제품 모델에 belongs_to 메소드를 정의합니다.
사용자 및 제품 모델에 대한 연결 정의
UserモデルとProductモデルにアソシエーション定義
# User.rb
class User < ActiveRecord::Base
has_many :Products
end
# Product.rb
class Product < ActiveRecord::Base
belongs_to :User
end
모든 소유의 상품 일람」을 view로 표시하고 싶은 경우에, controller측에서 모든 user를 all 메소드로 취득해, view측에서 주인이 가지는 products를 어소시에이션에 의해 아래와 같이 기술할 수가 있습니다.
N+1 문제가 발생하는 코드 확인
# controller
@users = User.all
# view
@users.each do |user|
user.products.each do |product|
product.name
end
end
「User.all」의 코드가 실행되면, 「users 테이블로부터 users 테이블의 모든 컬럼」이 취득.
이 SQL에 의해, users 테이블에 1회의 액세스.
다음에 veiw측. SQL을 보면, products 테이블에 대해, 4회의 액세스가 행해지고 있다.
N+1 문제가 발생하는 코드@groups.each do |group|
group.products.each do |product|
cat.name
end
end
# このコードが4回のSQL文を発行
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 1
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 2
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 3
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 4
each 메소드에서 @groups이 가진 users 테이블에서 모든 레코드를 하나씩 그룹에 넣고 있습니다.
SQL이 "users 테이블에 대한 액세스가 한 번"에 대해 "products 테이블에 대한 액세스가 그룹 테이블의 레코드 수 (4 회)"발행
이와 같이 액세스 1회에 대하여, 관련 테이블이 N회 발행되고 있는 1+N의 상황을 「N+1 문제」라고 한다.
.
N+1 문제 해결
includes 메소드
includes 메소드includesメソッドの使用例 -->
@users = User.includes(:user)
@users = User.allで取得していた箇所を@users = User.includes(:products)に変更します
includes 메소드@users = User.includes(:products) # User.allから変更
# 発行される2つのSQL
SELECT `users`.* FROM `users`
SELECT `products`.* FROM `products` WHERE `products`.`group_id` IN (1, 2, 3, 4)
두 개의 SQL이 발행되었습니다. 첫 번째 줄은 users 테이블의 모든 레코드를 검색하는 SQL 문입니다.
두 번째 행은 제품 테이블에서 WHERE 절에 지정된 조건과 일치하는 레코드를 검색합니다.
요약
includes 메소드를 사용하지 않는 경우는, 관련하는 user_id 컬럼의 값을 1개씩 지정해 취득하고 있었으므로 products 테이블에 4회의 액세스가 필요했습니다만, IN구로 컬럼의 값을 정리해 지정했다 일에 의해 1회로 취득할 수 있게 되었습니다. includes 메소드를 사용하여 레코드를 수집하여 필요 이상으로 SQL을 발행하지 않고 성능을 향상시킬 수 있습니다.
Reference
이 문제에 관하여(【Rails】N+1 문제에 대한 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/kinoshitaken123/items/fb67f7de37c2ff4f0ba2
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Product Load (2.7ms) SELECT `products`.* FROM `products`
UserモデルとProductモデルにアソシエーション定義
# User.rb
class User < ActiveRecord::Base
has_many :Products
end
# Product.rb
class Product < ActiveRecord::Base
belongs_to :User
end
# controller
@users = User.all
# view
@users.each do |user|
user.products.each do |product|
product.name
end
end
@groups.each do |group|
group.products.each do |product|
cat.name
end
end
# このコードが4回のSQL文を発行
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 1
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 2
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 3
SELECT `products`.* FROM `products` WHERE `products`.`group_id` = 4
includes 메소드
includes 메소드
includesメソッドの使用例 -->
@users = User.includes(:user)
@users = User.allで取得していた箇所を@users = User.includes(:products)に変更します
includes 메소드
@users = User.includes(:products) # User.allから変更
# 発行される2つのSQL
SELECT `users`.* FROM `users`
SELECT `products`.* FROM `products` WHERE `products`.`group_id` IN (1, 2, 3, 4)
두 개의 SQL이 발행되었습니다. 첫 번째 줄은 users 테이블의 모든 레코드를 검색하는 SQL 문입니다.
두 번째 행은 제품 테이블에서 WHERE 절에 지정된 조건과 일치하는 레코드를 검색합니다.
요약
includes 메소드를 사용하지 않는 경우는, 관련하는 user_id 컬럼의 값을 1개씩 지정해 취득하고 있었으므로 products 테이블에 4회의 액세스가 필요했습니다만, IN구로 컬럼의 값을 정리해 지정했다 일에 의해 1회로 취득할 수 있게 되었습니다. includes 메소드를 사용하여 레코드를 수집하여 필요 이상으로 SQL을 발행하지 않고 성능을 향상시킬 수 있습니다.
Reference
이 문제에 관하여(【Rails】N+1 문제에 대한 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/kinoshitaken123/items/fb67f7de37c2ff4f0ba2
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(【Rails】N+1 문제에 대한 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/kinoshitaken123/items/fb67f7de37c2ff4f0ba2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)