Prefetch 란
perfetch_related 함수는 쿼리에서 Join을 하지 않고, 개별 쿼리를 실행 한 후 django에서 직접 데이터를 조합하는 것
예시) A, B, C 모델이 존재 / A:B 는 1:N / B:C 는 1:N의 관계를 가짐
비교 1 ) A에서 C 까지의 Prefetch
1안. Prefetch 병렬로 쓰기
a = (
A.objects.filter(id=1).prefetch_related(
Prefetch(
"b_set", # A에서 B 역참조
),
Prefetch(
"b_set__c_set", # A에서 C역참조
),
)
).first()
2안. Prefetch 중첩해서 쓰기
a = (
A.objects.filter(id=1).prefetch_related(
Prefetch(
"b_set", # A에서 B역참조
queryset=B.objects.all().prefetch_related(
Prefetch(
"c_set", # B에서 C 역참조
)
),
),
)
).first()
결론적으로 1안과 2안의 결과(쿼리 포함)는 동일하다.
1안의 경우 A입장에서 C까지 prefetch 하는 과정이 두번의 Prefetch를 타고 가야해서, 부적절해 보일 수 있으나,
django의 Prefetch는 알아서 최적화(조합)을 해주기 때문에 같은 의미임.
단. 실제 가독성 측면에서 2번이 더 좋아 보이기도 하지만, 팀 규칙으로 정할 문제.
비교 2 ) filter와 prefetch의 관계
1안
# filter 의미
a = (
A.objects.filter( # inner join 수행됨
B_set__C_set_field_c__gte=10, # C테이블의 field_c가 10이상의 값인 것들 추출
)
)
- filter에서 B와 C에 id 필드 들에 대해, inner join을 수행
- 결국 C의 c가 유효한 A를 구하는 것 (유효한 C에서 구하는 것이 아닌 A를 구하는데 사용되고 끝)
- 만약 B와 C가 N개씩 존재한다면, 매번 B * C 갯수만큼 쿼리를 매번 호출 할 것
2안
a = (
A.objects.filter().prefetch_related(
Prefetch(
"B_set__C_set", # 각기 SELECT 쿼리가 실행됨
queryset=C.objects.filter(c__gte=10),
)
)
).first()
- prefetch 에서 B와 C에 id 필드 들에 대해, SELECT 조회 쿼리가 수행됨
- 이 결과를 django에서 합침
- 결국 유효한 c를 가진 C를 구해서, A에 붙이는 것
- B에 대한 SELECT 쿼리, C에 대한 SELECT 쿼리가 추가로 수행됨
'Python > Django' 카테고리의 다른 글
[Django, DB] haversine 두 지점의 거리 Django Func 사용하기 (0) | 2024.06.30 |
---|---|
[Django] Django Models 와 @property (1) | 2024.06.16 |
[Django] Django Model - Table Field, Relationship (1) | 2023.02.07 |
[Django] 간단한 메일 전송 기능 구현 (by. Gmail ) (0) | 2022.11.18 |
[Django] Pagination 방법 비교 (Feat. Django, DRF) (0) | 2022.11.10 |