본문으로 바로가기

[Django] Select && Prefetch Related !

category Frame Work/Django 2022. 2. 20. 22:55
728x90
반응형
 

개요

Django ORM에서 참조 관계에 있는 모델 간에 데이터를 가져오게 될 때 사용하는 select_related & prefetch_related가 무엇인지 조사해봤다.

 

Model

이 포스팅에서 사용할 모델은 다음과 같다.

from django.db import models

class Machine(models.Model):
    name = models.CharField(max_length=120)

class History(models.Model):
    # 객체 이름을 참조할 떄는 string으로 circular import 방지를 위해
    machine = models.ForeignKey("Machine", related_name="history_set", on_delete=models.CASCADE)
    objects = models.Manager()
조사하다가 알게 된 사실인데 ForeignKey를 사용할 때 모델을 명시해주는 부분에 String으로 선언되있는 이유는 Comment에도 적어놨듯 Circular import를 방지하기 위해서다. 이 방법은 Django Guide를 읽다가 발견했는데 링크는 추후에 첨부해야겠다.
 
 

Select Related?

Selected Related는 정방향 참조, 정참조 라고 부른다. 내가 참조하는 table에 접근한다 라고 정의할 수 있는데  위의 Model을 예로 들었을 때,  History 모델의  `machine`이라는 속성이 ForeignKey로 연결된 Machine의 데이터를 가져오는 경우이다.
즉, 1:N의 관계에서 N쪽에 있는 곳이 사용할 수 있다. Django ORM의 코드는 다음과 같이 생겨먹었다.
history = History.objects.select_related('machine')

위 구문이 실행하는 SQL을 보게 되면 다음과 같다.

SELECT `app_history`.`id`,
       `app_history`.`machine_id`,
       `app_machine`.`id`,
       `app_machine`.`name`
FROM `app_history`
INNER JOIN `app_machine` ON (`app_history`.`machine_id` = `app_machine`.`id`)
LIMIT 21
DB에서 Join을 한 결과를 가져오고 Prefetch와 비교해보면 쿼리가 1번만 발생한다는 점도 알 수 있다.

 

 

Prefetch Related?

Prefetch Related는 역방향 참조, 역참조라고 부른다. 나를 참조하는 table에 접근한다라고 정의할 수 있는데 위의 Model을 예로 들었을 때 Machine 모델에서 자기를 참조하고 있는 History 모델의 데이터를 가져오는 경우이다.
즉 1:N의 관계에서 1쪽에 있는 곳이 사용할 수 있다. Django ORM 코드는 다음과 같이 생겨먹었다.
machine_qs = Machine.objects.prefetch_related('history_set').all()

위 구문이 실행하는 SQL을 보게 되면 다음과 같다.

(0.005) | SELECT `app_machine`.`id`,
        |        `app_machine`.`name`
        | FROM `app_machine`

(0.012) | SELECT `app_history`.`id`,
        |        `app_history`.`machine_id`
        | FROM `app_history`
        | WHERE `app_history`.`machine_id` IN (1,
        |                                      301,
        |                                      302,
        |                                      303)

쿼리가 2번 발생하는 것을 알 수 있다. 즉 Python에서 join 기능을 수행한다.

728x90
반응형