Rails: Joins, Preload, Eager load and Includes

HyoKwangRyu·2020년 9월 13일
3

Ruby on Rails

목록 보기
1/6

Joins

association 데이터 로딩 없이 inner join을 실행 함. (association 은 모델간의 관계)
적어도 하나 이상의 relation 레코드와 매치해야 하고, 이로 인해 중복 레코드가 반환 될 수 있다.

User.joins(:resumes).where(id: 150864)

-> SELECT `users`.* FROM `users` INNER JOIN `resumes` ON `resumes`.`user_id` = `users`.`id` AND `users`.`id` = 150864

해당 resume 의 갯수만큼 user 가 리턴될 수 있다.

Eager load

left outer join 을 한다.
-> 모든 associations를 단일 쿼리로 로드 함.

association이 메모리에 로드되므로 association에 액세스하려는 경우에만 사용되며, where 절이 지원되거나 모든 association을 단일 쿼리로 가져 오도록 association을 기준으로 레코드를 필터링하려는 경우에 사용된다.

보통 디벨롭 환경 config에서 eager_load 를 false로 하고, 프로덕션 환경에서는 true로 함.
eager_load는 startup 시에 레일즈가 앱의 모든 것을 로드하므로 startup time이 늘어난다.

User.eager_load(:resumes).where(id: 150864)

-> 쿼리가 너무 길어서 생략..

Preload

association 데이터를 로드하기위한 별도의 쿼리가 생성 됨.(association 당 하나의 쿼리).
association에 대한 필터를 적용하지 않고 메모리에 로드되므로, association에서 where 및 find_by 같은 조건절을 쓸 수 없고 오류가 발생 함.
그러나 부모 assocation 자체에서 사용할 수 있다.

User.preload(:resumes)

> SELECT `users`.* FROM `users`
> SELECT `resumes`.* FROM `resumes` WHERE `resumes`.`user_id` IN (1)

Includes

기본 동작은 preload이지만, preload와는 달리 association에 where 절을 적용하여 동작을 eager_load로 변경하거나, 이를 기본 동작으로 사용하려는 경우 reference를 사용할 수 있다.
left_outer_join 으로 생각하자

User.includes(:resumes)

> SELECT `users`.* FROM `users`
> SELECT `resumes`.* FROM `resumes` WHERE `resumes`.`user_id` IN (1)

두 개의 쿼리가 user, resume에 대한 데이터를 가져온다.

User.includes(:resumes).references(:resumes)

SELECT “users”.”id” AS t0_r0, “resumes”.”id” AS t1_r0 FROM “users” LEFT OUTER JOIN “resumes” ON “resumes”.”user_id” = “users”.”id” WHERE “users”.”id” IN (1)

단일 쿼리가 user, resume 모두에 대한 데이터를 가져온다.

결론

대부분의 경우 joinsincludes을 사용하지만, 상황에 따라 쿼리를 최적화 할 수 있도록 preload 및 eager_load에 대한 지식을 가지고있는 것이 좋을 것 같다.

(근데 아직 eager_load 잘 이해못함.)

profile
Backend Developer

0개의 댓글