[Django] ORM 'prefetch_related'와 'select_related'

solved_err.log·2022년 10월 18일
0
post-thumbnail

편리하면서도 은근히 사용하기 복잡한 Django의 ORM,
그 중 prefetch_related와 select_related에 대해 자세히 알아보자.

먼저, ORM이란 무엇일까?

Object Relational Mapping, 객체-관계 매핑을 뜻하는 용어로, 객체와 관계형 데이터베이스의 데이터를 자동으로 연결해주는 것을 의미한다.


Foreign Key 속성이 있는 객체에서 해당 부모를 참조하거나 1:1 관계에서 참조하는 경우

Query문의 Join을 사용해 foreign-key(one to one, many to one)를 참조하며, 관련된 테이블 정보를 받아올 수 있다.

다음의 예시와 함께 확인해보자.
"나는 user id가 1인 사람의 도시 명을 알고 싶다."
(User: 자식 테이블, City: 자식이 참조하는 부모 테이블)

# 도시 정보
class City(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=20)

# 유저 정보
class User(models.Model):
	id = models.BigAutoField(primary_key=True)
    city = models.ForeignKey('City', on_delete=models.CASCADE)
	name = models.CharField(max_length=20)
	age = models.SmallIntegerField()
  1. select_related 사용 X
  city_info = User.objects.get(id=1).city
  city_name = city_info.name
  1. select_related 사용 O
  city_info = User.objects.select_related('city').get(id=1).city
  city_name = city_info.name

위의 1과 2 방법은 쿼리 상으로는 다를 게 없어 보인다. 오히려 2번이 더 복잡해 보이기도 한다. 그렇다면, DB 접근 방식을 비교해보자.

1번의 경우, DB에 2번의 접근을 하게 된다.
User 테이블에서 id가 1번인 유저의 city 값을 가져오기 위한 조회 -- (1),
가져온 1의 데이터를 바탕으로 City 테이블을 조회해 name 값을 가져오기 위한 조회 -- (2)

하지만, select_related를 사용한 2번의 경우 DB에 1번만 접근한다.
select_related에서 관련된 Object(여기서는 city)까지 한 번에 조회해 cache에 저장한다.
따라서, 이후에 city 값에 대한 조회를 할 때는 DB에 재접근 방식이 아닌 가져온 cache 값에서 꺼내서 사용하기만 하면 된다.

➰ select_related는 INNER JOIN을 통해 데이터를 가져온다.
➰ foreign-key, one-to-one과 같은 1:1 관계에서 사용하는 것이 효과적이다.


정참조를 포함하여, 역참조(다른 객체가 ForeignKey를 가지고 있거나 M:N 관계일 때, 해당 객체를 참조하고 있는 다른 객체를 참조)하는 경우 사용한다.

➰ prefetch_related는 foreign-key, one-to-one 뿐만 아니라 many-to-many, many-to-one 관계에서도 사용 가능하다.
➰ SQL에서 각 모델을 조회하고, Python에서 Join을 실행한다.

간단한 테이블 및 구조로 확인해 보았지만, 데이터가 많아지고 연관된 테이블이 많아질 경우 DB 접근 방식에 따른 쿼리 성능은 무시할 수 없다.

상황에 맞게 select_related와 prefetch_related를 사용해 효율적인 코딩을 해보자!😆

profile
배우고 기록하는 개발 일기장✍

0개의 댓글