오늘의 호기심 해결 주제는 Django의 request.session.get()이 성능 저하를 일으키는가? 입니다! 🎯

Django 개발을 하면서 request.session.get('key_name')을 여러 번 호출하는 경우가 많죠? 그런데 문득 이런 생각이 들었습니다.

"세션도 결국 DB에 저장되는 거라면, request.session.get()을 호출할 때마다 DB 쿼리가 발생하는 걸까?"

"아니면 Django가 뭔가 똑똑한 처리를 해두어서 추가적인 쿼리가 발생하지 않는 걸까?"

이 궁금증을 해결하기 위해 Django의 SessionMiddleware 소스 코드 깊숙한 곳까지 파헤쳐 보고, 실험을 통해 확인해보았습니다. 🚀

1️⃣ Django에서 request.session은 어떻게 생성될까?

Django가 request 객체를 만들 때 세션을 언제 로드하는지 알아보겠습니다.

Django session management process

우리는 보통 뷰 함수에서 이렇게 세션 데이터를 가져옵니다.

session_username = request.session.get('username')

그런데 request.session.get('username')을 사용할 때마다 Django가 DB 쿼리를 날리는 것이라면, 성능에 큰 영향을 미칠 수도 있겠죠?

🔍 Django 내부를 살펴보자!

사실 Django는 SessionMiddleware라는 미들웨어를 통해 요청이 들어올 때 세션 데이터를 미리 로드해둡니다. 이 과정에서 DB 쿼리가 딱 한 번 발생하고, 이후에는 request 객체 안에 세션 데이터를 유지하게 됩니다.

Django의 SessionMiddleware 코드를 보면 다음과 같은 처리가 이루어집니다.

class SessionMiddleware(MiddlewareMixin):
    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)

📌 여기서 중요한 점!

  • request.COOKIES에서 세션 키(session_key)를 가져온다.
  • self.SessionStore(session_key)를 호출하여, 세션 데이터를 한 번만 DB에서 가져와 request.session에 저장한다.
  • ✅ 즉, 뷰 함수에서 request.session.get()을 여러 번 호출하더라도 추가적인 DB 쿼리는 발생하지 않는다! 🎯

2️⃣ request.session.get()은 DB 쿼리를 발생시키는가?

이제 핵심 질문으로 돌아가 보겠습니다.

"뷰에서 request.session.get('username')을 호출하면 DB 쿼리가 발생하는가?"

🚀 결론부터 말하면, request.session.get()을 호출해도 추가적인 DB 쿼리는 발생하지 않습니다.

이유는 간단합니다.
✔ Django는 요청이 들어올 때 세션 데이터를 한 번 로드한 후, request.session에 저장합니다.
✔ 이후 request.session.get()을 호출하는 것은 이미 메모리에 로드된 데이터를 가져오는 것이므로 추가적인 DB 조회가 필요하지 않습니다.

실제로 DB에서 세션을 조회하는 순간은 요청 초기에 한 번뿐입니다. 이때 실행되는 SQL 쿼리는 다음과 같습니다.

SELECT session_data FROM django_session WHERE session_key = 'xyz123' LIMIT 1;

 즉, ✅ 뷰에서 request.session.get()을 여러 번 호출해도 Django는 추가적인 DB 쿼리를 실행하지 않는다!
      ✅ DB에서 데이터를 불러오는 것은 요청이 처음 발생했을 때 단 한 번만 실행된다!

3️⃣ 템플릿에서 세션 데이터를 사용할 때도 쿼리가 발생할까?

"뷰에서 세션 데이터를 조회한 뒤 템플릿으로 넘기고, 템플릿에서 이를 사용할 때도 추가적인 DB 쿼리가 발생할까?"

예를 들어, 뷰에서 세션 데이터를 이렇게 넘긴다고 가정해봅시다.

def my_view(request):
    session_username = request.session.get('username')  # DB 조회 발생? ❌
    return render(request, 'my_template.html', {'session_username': session_username})

그리고 템플릿에서 이렇게 사용한다고 해볼게요.

<p>Logged in as: {{ session_username }}</p>

이 경우에도 추가적인 DB 쿼리는 발생하지 않습니다!

session_username이미 request.session에서 가져온 값이므로, Django가 이를 템플릿으로 넘길 때 추가적인 DB 조회는 필요하지 않습니다.

✔ Django는 request.session메모리 캐시처럼 관리하기 때문에, 템플릿에서도 안전하게 사용할 수 있습니다.


4️⃣ 세션 데이터를 변경하면 DB에 저장될까?

"그럼 request.session['username'] = 'new_value'처럼 데이터를 변경하면?"

🚀 이 경우에는 DB에 변경 사항이 저장되면서 추가적인 DB 쿼리가 발생합니다!

만약 아래와 같이 세션 데이터를 변경하면,

request.session['username'] = 'new_value'

Django는 응답을 보낼 때 변경된 세션 데이터를 DB에 저장합니다. 이때 실행되는 SQL 쿼리는 다음과 같습니다.

UPDATE django_session SET session_data = 'new_value' WHERE session_key = 'xyz123';

세션을 읽는 것은 DB 쿼리를 발생시키지 않지만, 세션을 변경하면 Django가 이를 저장하기 위해 DB에 쿼리를 실행합니다.


5️⃣ 세션 저장 방식(백엔드)에 따른 차이

Django에서는 세션을 저장하는 방식(백엔드)을 변경할 수 있습니다. 백엔드에 따라 쿼리 발생 여부가 달라질 수 있음을 주의해야 합니다.

세션 백엔드 설명 DB 쿼리 발생 여부
django.contrib.sessions.backends.db 기본 DB 기반 세션 ✅ 요청 시 한 번 발생
django.contrib.sessions.backends.cache 캐시 기반 세션 (Redis, Memcached) ❌ DB 쿼리 없음
django.contrib.sessions.backends.cached_db 캐시 + DB 세션 (캐시 없으면 DB 조회) 🚀 캐시에 없으면 발생
django.contrib.sessions.backends.signed_cookies 쿠키 기반 세션 ❌ DB 쿼리 없음

🚀 즉, cachesigned_cookies 백엔드를 사용하면 DB 쿼리 없이 세션을 가져올 수도 있습니다. ✔ 성능이 중요한 경우 CACHED_DB_SESSION을 고려하는 것도 좋은 방법입니다.


🎯 결론

  • ✅ Django는 요청(Request) 초기에 SessionMiddleware를 통해 세션 데이터를 미리 로드하여 request.session 객체에 저장합니다.
  • ✅ 따라서, 뷰에서 request.session.get('username')을 호출하는 것은 추가적인 DB 쿼리를 발생시키지 않습니다.
  • 템플릿에서 세션 데이터를 사용할 때도 추가적인 DB 쿼리는 발생하지 않습니다.
  • ✅ 하지만, 세션 값을 변경하면 Django가 응답을 보낼 때 DB에 변경된 데이터를 저장합니다.
  • ✅ Django의 세션 백엔드 설정에 따라 쿼리 발생 여부가 다를 수 있으므로, 캐시 기반(cache 또는 cached_db)을 사용하면 DB 부하를 줄일 수 있습니다.

🔥 다음 화 예고: request 객체는 언제 사라질까?

그렇다면 request 객체는 언제 사라질까요?

  • 요청이 끝나도 계속 메모리를 차지하고 있는 걸까요?

  • 시스템에서 자동으로 청소해주나요, 아니면 우리가 직접 정리해야 할까요?

🚀 다음 화에서는 Django의 request 객체의 수명과 메모리 관리에 대해 탐구해 보겠습니다! 기대해 주세요! 😃