[Django]Django ORM이 작성하는 SQL 보는 방법

David Im·2022년 4월 9일
0

본 글은 야간모드에 최적화 되어있습니다. 우측 상단에서 해 혹은 달모양을 클릭시어 velog 설정을 야간모드로 해주시면 더욱 편안하게 읽으실 수 있습니다.


Django의 ORM은 굉장히 강력하다.

요새 Spring 강의를 듣고 있지만, Spring의 ORM인 Hybernate의 annotation을 보고있다가 Django의 ORM을 보는 순간 정말 편하다 라고 느낀다.

물론, ORM을 너무 맹신하지는 말자.

나중 글에 올리겠지만 ORM을 맹신하다가 API 성능에서 크게 손해를 본 적이 있었다.

그래서 요새는 ORM도 ORM이지만 Read DB에서 직접 SQL을 다루는 것 자체를 좀 더 선호하게되었다.

SQL query 자체에 약한 부분도 있었는데 요새 SQL 자체로 직접 짜보게 되면서
오히려 반대로 이제는 SQL로 되는걸 어떻게 ORM으로 바꾸지? 라는 걸 더 고민할 때가 많다.


각설하고 본문으로 넘어가서 Django ORM이 동작시에 작성하는 SQL을 볼 수 있는 방법이 있다.

실제로 내가 만든 SQL과 ORM이 뽑아대는 데이터가 동일한다 비교할 때 나는 주로 사용하곤 하는데

회사에서는 실제로 근무하고 있는 사람이 대다수가 주니어들이다보니
아무리 같은 조건을 주어도 사람마다 작성하는 ORM이 다르고, SQL이 다를때가 있어서
개발자 간에 뽑아낸 데이터가 서로 다른 부분이 있다면 Cross Check하는 경우에 사용한다.


Django ORM이 동작시에 작성하는 SQL 보기

아주 간단하게 예를 들어보겠다.

아래의 사용자 guid list안에 들어있는 id만 뽑을때 우리는 아래와 같은 ORM을 작성한다.

guid_list = [a1234,b4893,c0273,k6292]
User_list = User.objects.filter(guid_id__in__guid_list)

해석해보면

' User라는 Model에서 guid_list에 속하는 guid값을 가진 data를 filtering해라.'

라고 볼 수 있다.

그럼 우리가 생각할때 저 조건에 맞는 SQL은?


간단하다. 아래와 같이 짜게 된다.

guid_list = (a1234,b4893,c0273,k6292)

select *
from user
where guid in guid_list

django ORM이 짜는것 역시 위에 guid를 array로 선언했냐 ()로 선언했냐의 차이일 뿐 동일하다.


ORM이 짠 쿼리를 확인하는 방법은 아래와 같이

print로 출력할때 str로 감싸 string형식으로 붙여준 후 queryset을 저장하고 있는 변수에 .query를 붙여주면 된다.


guid_list = [a1234,b4893,c0273,k6292]
user_list = User.objects.filter(guid_id__in__guid_list)

print(f'ORM query :: {str(user_list.query)})

결과는 SQL문으로 아래처럼 출력시켜준다.

그대로 복사해서 DB에서 SQL로 검색해도 잘 나온다.

ORM query :: SELECT * FROM USER WHERE guid IN (a1234,b4893,c0273,k6292)

Django ORM query를 볼 경우 주의 할 점

위에서 서술한것처럼 간단한 쿼리나 미친듯이 복잡한 쿼리가 아닌 경우에는 filter나 간단한 inner join, outer join 정도는 표기가 가능하다.

하지만 해당 방법에도 단점은 있다.

  1. 모든 ORM이 query문으로 바꾸어서 볼 수는 없다.
    가장 치명적인 단점이라고 본다.

    어지간한 쿼리들은 대부분 변경해서 보여주지만, inner join, outer join, union과 같이 여러 데이터를 한번에 보여주는 것이 진짜 극단적으로 많이 가거나 FK를 타고 여러번 헤집는 데이터를 보여준다던가 하게되면 ORM에서는 동작을해도 ORM이 작성한 SQL을 가지고 DB에서 볼 수 없는 경우가 있거나, 아예 print로 SQL query를 보려고할 때 출력해주지 못하는 경우가 있다고 한다.

    나는 아직까지 그렇게 극단적인 ORM을 짜본 적은 없지만... 스택오버플로우에서 본 적이 있다.

    아마 우리 회사의 트래픽이 그만큼 늘어나게되면 사용하게 되지 않을까 싶기도 하고...?


  1. ORM이 작성한 SQL query의 성능이 내가 작성한 SQL query보다 성능이 좋지 않을 수 있다.
    대부분은 그럴일이 거의 없겠다만, inner join, outer join, union등을 사용하게 되고 조건이 많이 붙게 된다면,
    내가 직접 작성한 sql query 보다 성능이 딸릴 수도 있다.

    글 시작할 때 작성했던것처럼 ORM을 너무 맹신하게 되면 안된다.

    ORM이 작성한 query는 실제로 DB access를 여러번 시도하는 것일 수도 있고,
    한번에 가져온다고 하더라도 그 아래에 연결된 FK를 타고 데이터를 호출한다던가 하는것을 조건으로 달게 되면
    오히려 그 ORM의 SQL문 성능이 우리가 작성한 SQL의 성능보다 낮은 결과를 보일 수 있으니
    적절히 크로스 체킹만 하는 용도로 사용하자.

    한가지 케이스로 내가 예전에 작성했던 ORM에 대해서 성능이 너무 좋지 않아 다른 방식으로 변경해보려고 했었는데 내가 작성한 SQL을 ORM으로 변경한것과 Django에서 조건대로 박아넣었던 ORM이 작성한 query의 성능이 극단적으로 차이를 보였던 경우가 있었다.
  1. ORM으로 바꾼 query문의 경우 error가 날때가 있지만 대부분 해결이 가능한 error이니 침착하자.

    string과 같은 조건들은 실제 어떤 DB툴을 사용하느냐에 따라 조금씩 다른데, 대부분이 syntax error인 경우가 대부분이다.

    '', "" 등을 인식못하거나, string 조건에 '', ""등이 들어가지 않아있거나, 줄바꿈 및 들여쓰기 등을 연달아 가져오는 경우가 있어 출력된 query문을 DB SQL 검색기에 붙여서 돌리려고하면 error가 날때가 있다.

    즉, django ORM query에서 보여주는 값이 string에 대해 ""처리를 해주지 않거나, 줄바꿈문장으로 SQL query문이 그대로 붙어서 들어가 sytax error인 경우가 많기때문에 사용하는 DB tool에 따라 확인이 필요하다.

    나는 DBeaver를 사용중인데 string형식으로 넣은 조건에 ""와 같은 것들이 Django에서 보여주지 않아 일일히 붙여줘야했다.

최종 정리

Django ORM은 강력하다. 편하다.

진짜 한번 접하고 나니 다른 ORM에서는 해주지 않는것들까지 지원해줘서 개발자 커뮤니티에서
본 글 중에서는 굳이 안해줘도 되는것까지 다 넣어서 오히려 불편한것도 있다고 할 정도로 잘 만들었다고 생각할 정도라더라.

하지만 데이터 검증이나 실제로 SQL query를 가지고서 데이터를 직접 봐야하는 경우나 API를 작성하기위해 ORM을 사용했을때 우리가 짠 ORM과 SQL의 데이터가 맞지 않는 경우가 있을 수 있다.

그럴때 크로스 체크 해보는 용도로만, 참고하는 용도로만 사용해보면 좋을 것 같다.

아니면 두번째 용도로는 '아 이조건 어떻게 SQL 짜야되지? 난 SQL은 경험이 적어서 아직 자신 없는데' 와 같은 주니어들에게는 극단적인 ORM이 아니고서는 참고 할 만하다.

내가 머리아프게 짤 필요 없이 저렇게 .query로 한번에 볼 수 있으니까!

profile
코더보다 개발자로, 결과와 과정의 시너지를 만들어 가고 싶은 주니어 개발자

0개의 댓글