preload, eager_load, includes 정보
저는 주식회사에서 엔지니어로 일하는 iLviA입니다.
성능 저하를 초래하는 "N+1"문제이를 없애는 방법으로는 액티브 레코드
preload
,eager_load
,includes
가 준비됐다.이런 방법들은'어떤 행동을 할 것인가','어떤 장소에서 따로 사용할 것인가'를 이해하지 못한 채 많이 사용
includes
해 이해를 깊게 하기 위해 총결산했다.연관성
Article
는 중간표ArticleTag
를 통해'루비','자바스크립트','PHP'등 여러 개Tag
와 연결된다.Model
class Article < ApplicationRecord
has_many: :article_tags
has_many: :tags, through: :article_tags
end
class Tag < ApplicationRecord
has_many: :article_tags
has_many: :articles, through: :article_tags
end
class ArticleTag < ApplicationRecord
belongs_to: :articles
belongs_to: :tags
end
갖가지 방법preload
->원인은 최초로 발행된 조회에서where문이 작용했기 때문이다.
preload
에서 축소를 원할 때 작용역에 축소 조건을 기술할 수 있습니다.Article.preload(:tags)
# SELECT "articles".* FROM "articles"
# SELECT "article_tags".* FROM "article_tags" WHERE "article_tags"."article_id" IN (1, 2, 3, ....)
Article.preload(:tags).where(tags: {id: 1})
# Mysql2::Error: Unknown column 'tags.id' in 'where clause': SELECT `articles`.* FROM `articles` WHERE `tags`.`id` = 1
Article.preload(:tags).where(tags: {id: 1}).to_sql
# SELECT "articles".* FROM "articles" WHERE "tags"."id" = 1
# preloadで絞り込みたい場合
class Article < ApplicationRecord
...
has_many :conditional_tags, -> {
where('id < ?', 100)
}, class_name: 'Tag'
end
# pry
Article.preload(:conditional_tags)
# SELECT `articles`.* FROM `articles`
# SELECT `tags`.* FROM `tags` WHERE (id < 100) AND `tags`.`article_id` IN (1, 2, 3, ...)
eager_loadLEFT OUTER JOIN
를 캐시합니다.preload
와는 달리 JOIN
했기 때문에 지정된 곳에서 축소할 수 있습니다.Article.eager_load(:tags).where(tags: {id: 1})
# SELECT `articles`.`id` AS t0_r0, `articles`.`title` AS t0_r1, `articles`.`body` AS t0_r2, `tags`.`id` AS t1_r0, `tags`.`name` AS t1_r1 FROM `articles` LEFT OUTER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` LEFT OUTER JOIN "tags" ON `tags`.`id` = `article_tags`.`tags_id` WHERE `tags`.`id` = 1
includespreload
, eager_load
는 따로 사용할 수 있다.지정한 관련자가 축소 또는 결합 처리를 하면
eager_load
와 같은 행위다.그렇지 않으면 그 행위는 preload
와 같다.여러 관련자를 지정한 경우'이 테이블은 eager load, 이쪽은 proeload'같은 행동은 하지 않습니다.
모든 지정된 관련은
preload
, eager_load
중 하나를 통일적으로 처리해야 한다.Article.includes(:tags)
# SELECT "articles".* FROM "articles"
# SELECT "article_tags".* FROM "article_tags" WHERE "article_tags"."article_id" IN (1, 2, 3, ....)
Article.includes(:tags).where(tags: {id: 1})
# SELECT `articles`.`id` AS t0_r0, `articles`.`title` AS t0_r1, `articles`.`body` AS t0_r2, `tags`.`id` AS t1_r0, `tags`.`name` AS t1_r1 FROM `articles` LEFT OUTER JOIN `tags` ON `tags`.`id` = `article_tags`.`tag_id` WHERE `tags`.`id` = 1
구분 사용preload
has_many
의 연관성has_one
, belongs_to
의 관련※
preload
에도 스코프를 사용하면 축소 가능eager_load
의 축소와 속도를 비교하면 10ms 정도eager_load
가 더 빠르다고 기록되어 있습니다.(왜 이렇게 빨라요? 그냥 공교롭게도 빨라요. 의견이 있으면 알려주세요includes
ludes의 조회는 상황에 따라 달라져서 제어할 수 없기 때문에 기본적으로 사용하지 않는 것이 좋습니다.
includes
에서 "N+1"문제를 피하는 곳용eager_load
,preload
으로 교체하면 성능이 향상될 수 있으니 시도해 보세요.최후
잘못된 인식이 있으면 지적해 주십시오
preload
,eager_load
,저는 includes
의 글을 많이 읽었습니다Rails.cache
,알았기 때문에 다음 조사를 하고 싶습니다.
Reference
이 문제에 관하여(preload, eager_load, includes 정보), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/iLLviA/items/a52bdec96c25ebdc8e4e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)