3.1 ORM

ORM의 장점과 사용하는 이유

ORM(Object Relational Mapping**)**은 관계 지향형인 데이터베이스와 객체를 연결해 주는 것으로 ORM을 사용하게 되면 개발자는 데이터베이스를 객체 지향 코드로 다룰 수 있습니다. 이는 SQL 쿼리문을 직접 작성할 필요가 없기 때문에 코드가 직관적이며 개발자의 생산성을 향상할 수 있습니다. 또 코드의 일관성을 유지하고 복잡성을 줄이는 데 도움이 됩니다. 또한 SQL Injection 공격을 방어하는 데도 도움이 됩니다. 그리고 여러 데이터베이스를 지원하기 때문에 데이터베이스를 이전하기도 비교적 쉽습니다. SQL Injection은 공격자가 악의적으로 입력값을 조작해 SQL 코드를 주입하고 데이터베이스에서 원하는 SQL 코드를 실행시키는 공격으로 데이터베이스의 값을 삭제하거나 데이터 유출이 발생할 수 있습니다. Django 에서는 사용자의 입력값을 SQL 쿼리에 직접 삽입하지 않고 매개변수(parameter) 화해서 SQL Injection 공격을 방어합니다.

ORM의 단점

ORM은 자동으로 생성된 SQL을 사용하기 때문에 최적화되지 않은 SQL이 사용될 경우 성능 저하가 발생할 수 있습니다. 또 특정한 데이터베이스 쿼리를 ORM에서 지원하지 않을 경우 개발자가 직접 SQL을 작성해야 할 수 있습니다. 그렇기 때문에 ORM에만 의존하는 것은 좋지 않으며 SQL에 대한 이해도 필요합니다.

기타 ORM

Django ORM 외에도 Python에는 SQLAlchemy, Peewee, Tortoise ORM 등의 ORM이 있으며 Java의 Hibernate 그리고 JavaScript의 Prisma, TypeORM 등이 있습니다.

예시

이번 장에서는 설명의 편의를 위해 아래의 Model과 데이터를 기반으로 예제 코드를 작성하였습니다. 데이터베이스는 PostgreSQL 15.4를 사용하였습니다.

from django.db import models

class Zoo(models.Model):
    zoo_name = models.CharField()

    def __str__(self):
        return f'{self.zoo_name}'

class Animal(models.Model):
    name = models.CharField()
    info = models.TextField()
    zoo = models.ForeignKey(Zoo, on_delete=models.CASCADE)
    medical_check = models.BooleanField()
    birth_at = models.DateTimeField()

    def __str__(self):
        return f'{self.name}'

스크린샷 2023-10-22 121332.png

쿼리셋의 특징

쿼리셋은 데이터베이스 쿼리 발생을 최소화하기 위해 데이터가 필요한 시점까지 쿼리를 최대한 지연시키고 데이터가 필요한 순간에 쿼리셋을 평가해 쿼리를 발생시킵니다. 또 쿼리셋이 평가되었다면 캐싱을 사용해 데이터를 재사용합니다. 하지만 캐싱 되는 데이터가 많다면 메모리 성능 저하가 발생할 수 있고 쿼리를 지연시키는 특징 때문에 N+1 문제가 발생할 수 있습니다. 이를 해결하기 위해 Django 에서는 쿼리를 지연시키지 않고 즉시 쿼리 하는 **select_related()**와 prefetch_related() 메소드를 제공하고 있습니다. 앞으로 배울 쿼리셋 평가 시기와 다양한 메소드, 쿼리셋 결합 방법 등을 잘 이해하고 효과적으로 쿼리셋을 최적화할 수 있는 능력을 갖출 수 있습니다.

3.2 쿼리셋 평가 시기

쿼리셋이 바로 평가 되는 경우

다음은 쿼리셋이 바로 평가되는 경우들입니다. SQL 쿼리가 발생하기 때문에 유의해야 합니다.