preload, eager_load, includes 정보

7311 단어 RubyRails
개시하다
저는 주식회사에서 엔지니어로 일하는 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_load
  • 지정된 관련자LEFT 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
    
    includes
  • 키하preload, 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의 연관성
  • 지정된 목표의 기록 수가 많음
  • eager_load
  • has_one, belongs_to의 관련
  • JOIN의 데이터 참조(필터링 결과 등)
    preload에도 스코프를 사용하면 축소 가능eager_load의 축소와 속도를 비교하면 10ms 정도eager_load가 더 빠르다고 기록되어 있습니다.(왜 이렇게 빨라요? 그냥 공교롭게도 빨라요. 의견이 있으면 알려주세요
  • 나는 각양각색의 보도를 읽었는데, 위에서 말한 구분 사용이 매우 보편적인 것 같다.
    includes
    ludes의 조회는 상황에 따라 달라져서 제어할 수 없기 때문에 기본적으로 사용하지 않는 것이 좋습니다.includes에서 "N+1"문제를 피하는 곳용eager_load,preload으로 교체하면 성능이 향상될 수 있으니 시도해 보세요.
    최후
    잘못된 인식이 있으면 지적해 주십시오preload,eager_load,저는 includes의 글을 많이 읽었습니다Rails.cache,알았기 때문에 다음 조사를 하고 싶습니다.

    좋은 웹페이지 즐겨찾기