Rails에서 N+1 문제를 해결하는 방법




🔑 4가지 주요 방법


  • 조인
  • 간절한 로드
  • 예압
  • 포함하다

  • 💎 조인



    INNER JOIN으로 통합
  • 은 연결을 캐시하지 않으므로 다시 생성되는 데이터가 필요하지 않은 경우 이를 사용해야 합니다.
  • ActiveRecord 객체가 캐시하지 않기 때문에 메모리 할당 공간을 절약합니다.

  • Skill.joins(:skill_category).limit(5)
    
    SELECT "skills".* 
    FROM "skills" 
    INNER JOIN "skill_categories" 
    ON "skill_categories"."id" = "skills"."skill_category_id" 
    LIMIT ?  [["LIMIT", 5]]
    


    💎 열망하는_부하



    캐시와 LEFT OUTER JOIN으로 통합
  • 하나의 SQL만 생성하기 때문에 preload()보다 빠릅니다
  • .
  • JOIN으로 통합된 테이블에서 WHERE를 사용할 수 있습니다(preload()는 할 수 없음).

  • Skill.eager_load(:skill_category).limit(5)
    
    SELECT "skills"."id" AS t0_r0, "skills"."name" AS t0_r1, "skills"."user_id" AS t0_r2, "skills"."skill_category_id" AS t0_r3, "skills"."created_at" AS t0_r4, "skills"."updated_at" AS t0_r5, "skill_categories"."id" AS t1_r0, "skill_categories"."name" AS t1_r1, "skill_categories"."reccomend" AS t1_r2, "skill_categories"."created_at" AS t1_r3, "skill_categories"."updated_at" AS t1_r4 
    FROM "skills" 
    LEFT OUTER JOIN "skill_categories" 
    ON "skill_categories"."id" = "skills"."skill_category_id" 
    LIMIT ?  [["LIMIT", 5]]
    


    💎 프리로드



    캐시와 함께 여러 SQL 사용
  • 조인
  • 하고 싶지 않은 큰 테이블이 있을 때 사용하는 것이 좋습니다.
  • * WHERE는 JOIN으로 통합되어 있지 않기 때문에 사용할 수 없습니다.

  • Skill.preload(:skill_category).limit(5)
    
    # this one
    SELECT "skills".* FROM "skills" LIMIT ?  [["LIMIT", 5]]
    # and this one
    SELECT "skill_categories".* 
    FROM "skill_categories" 
    WHERE "skill_categories"."id" 
    IN (?, ?, ?, ?, ?)  [[nil, 483], [nil, 583], [nil, 901], [nil, 181], [nil, 147]]
    


    💎 포함





    where, join, 적어도 하나의 방법을 사용하면 eager_load로 실행되고, 그렇지 않으면 미리 로드됩니다.

    # just includes
    Skill.includes(:skill_category).limit(5)
    
    # this one
    SELECT "skills".* FROM "skills" LIMIT ?  [["LIMIT", 5]]
    # and this one
    SELECT "skill_categories".* 
    FROM "skill_categories" 
    WHERE "skill_categories"."id" 
    IN (?, ?, ?, ?, ?)  [[nil, 483], [nil, 583], [nil, 901], [nil, 181], [nil, 147]]
    



    # using where()
    Skill.includes(:skill_category).where(skill_categories: { name: 'baseball' })
    
    # just one SQL like eager_load 👍
    SELECT "skills"."id" AS t0_r0, "skills"."name" AS t0_r1, "skills"."user_id" AS t0_r2, "skills"."skill_category_id" AS t0_r3, "skills"."created_at" AS t0_r4, "skills"."updated_at" AS t0_r5, "skill_categories"."id" AS t1_r0, "skill_categories"."name" AS t1_r1, "skill_categories"."reccomend" AS t1_r2, "skill_categories"."created_at" AS t1_r3, "skill_categories"."updated_at" AS t1_r4 
    FROM "skills" 
    LEFT OUTER JOIN "skill_categories" 
    ON "skill_categories"."id" = "skills"."skill_category_id" 
    WHERE "skill_categories"."name" = ?  [["name", "baseball"]]
    


    includes 방식은 보시다시피 편리하지만 다른 개발자가 include 방식을 볼 때 "preload"또는 "eager_load"를 의미한다고 생각해야 합니다.

    좋은 웹페이지 즐겨찾기