(개인 메모) Rails5 모델을 연결할 때 조심합시다.
7458 단어 RailsRails5association성능루비
전제
Rails에서 모델을 업데이트하는 코드를 쓰려고 생각 밖에 빠져서 변경하지 않는 관련시킨 모델도 로드시킨다
테이블 구조
이하 간단한 테이블을 만들어 보겠습니다.
우선 쓰자.
일단 자신이 생각하는대로 코드를 써 간다.
# app/models/product.rb
class Product < ApplicationRecord
belongs_to :category
belongs_to :main_image, class_name: 'PublicImage', foreign_key: :main_image_id
validates :name, uniqueness: true
end
좋은 느낌에 코드를 쓰고 있지만. . .
그러나 문제가 일어난다...
기존 레코드를 업데이트하면 로그에 쓸모없는 쿼리가 나오지 않습니다.
Product.first.update(name: "test")
Product Load (0.7ms) SELECT `products`.* FROM `products` ORDER BY `products`.`id` ASC LIMIT 1
(0.1ms) BEGIN
Category Load (0.6ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 1 LIMIT 1
PublicImage Load (0.2ms) SELECT `public_images`.* FROM `public_images` WHERE `public_images`.`id` = 1 LIMIT 1
Product Exists (0.8ms) SELECT 1 AS one FROM `products` WHERE `products`.`name` = BINARY 'black-ball' AND `products`.`id` != 1 LIMIT 1
(0.2ms) COMMIT
=> true
왜 Product 업데이트에만 Category와 PublicImage도 로드하고 있는지
조사해 보면 "Rails5에서 belongs_to 관련은 디폴트로 required: true가 된다"는 것을 알았습니다.
개선
required: false로 하고 싶을 때는 optional: true라고 쓸 수 있게 된다.
실감 required: true로 하고 싶습니다만, 그대로 쓰고 있으면 쓸데없는 query가 발생되고 있던 채 기분 나쁘습니다.
그럼, 다음의 쓰는 방법으로 해결합시다.
단순히 외래 키를 업데이트 할 때 유효성 검사를 수행합니다.
# app/models/product.rb
class Product < ApplicationRecord
belongs_to :category, optional: true
belongs_to :main_image, class_name: 'PublicImage', foreign_key: :main_image_id, optional: true
validates :name, uniqueness: true
validates :category, presence: true, if: :validate_category_presence?
validates :main_image, presence: true, if: :validate_main_image_presence?
private
def validate_category_presence?
new_record? || category_id_changed?
end
def validate_main_image_presence?
new_record? || main_image_id_changed?
end
end
결과
쉬운 개선이지만 속도의 효과는 대단합니다.
다음은 쉽게 검증하고 볼 수 있습니다.
a = Time.now
1000.times{Product.first.update(name: "test")}
b = Time.now
b - a
수정 전: 15.837107
수정 후: 5.362079
이상
Reference
이 문제에 관하여((개인 메모) Rails5 모델을 연결할 때 조심합시다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/nguyenduyta/items/1bec16d1b67cc00e44a4
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
# app/models/product.rb
class Product < ApplicationRecord
belongs_to :category
belongs_to :main_image, class_name: 'PublicImage', foreign_key: :main_image_id
validates :name, uniqueness: true
end
Product Load (0.7ms) SELECT `products`.* FROM `products` ORDER BY `products`.`id` ASC LIMIT 1
(0.1ms) BEGIN
Category Load (0.6ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 1 LIMIT 1
PublicImage Load (0.2ms) SELECT `public_images`.* FROM `public_images` WHERE `public_images`.`id` = 1 LIMIT 1
Product Exists (0.8ms) SELECT 1 AS one FROM `products` WHERE `products`.`name` = BINARY 'black-ball' AND `products`.`id` != 1 LIMIT 1
(0.2ms) COMMIT
=> true
# app/models/product.rb
class Product < ApplicationRecord
belongs_to :category, optional: true
belongs_to :main_image, class_name: 'PublicImage', foreign_key: :main_image_id, optional: true
validates :name, uniqueness: true
validates :category, presence: true, if: :validate_category_presence?
validates :main_image, presence: true, if: :validate_main_image_presence?
private
def validate_category_presence?
new_record? || category_id_changed?
end
def validate_main_image_presence?
new_record? || main_image_id_changed?
end
end
a = Time.now
1000.times{Product.first.update(name: "test")}
b = Time.now
b - a
Reference
이 문제에 관하여((개인 메모) Rails5 모델을 연결할 때 조심합시다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/nguyenduyta/items/1bec16d1b67cc00e44a4텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)