[Django] Model.objects.bulk_create()를 통한 한번에 저장

Junseo Jung·2024년 4월 2일
0

Django

목록 보기
1/4
post-thumbnail

문제 상황

  1. delete - 빌딩 (1440 row)
  2. select - 빌딩 (1440 row)
  3. insert - 빌딩(1440 row) - bulk_create()로 개선
  4. delete - 스케줄(3870 row)
  5. insert - 스케줄 (3870 row) - bulk_create()로 개선

Django로 개발하던 중 API로 요청이 올 때마다 요청에 맞게 테이블의 값을 모두 delete하고 다시 insert해야하는 상황이 발생했다. DB를 최대한 유지하고 싶었으나 요구사항을 만족시키기 위해 어쩔수 없이 모두 지우고 다시 만들어야 했다.

로직에 맞게 값을 구하고 구한 값을 바탕으로 for문을 통해 반복하며 Model.object.create().save()로 insert쿼리를 날리게 되었다. 그 결과 API조회 시 약 5초의 시간이 발생하게 되었고 이를 줄이고자 방법을 찾게 되었다.

bulk_create()

객체 리스트를 통해 효율적으로 DB에 저장한다. for문을 사용해서 save()시 모든 save마다 DB connection을 발생하는 반면 bulk_create()는 하나의 connection을 통해 insert를 수행한다.

매개변수

bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
  • batch_size: 한 개의 쿼리에 얼마나 많은 객체를 넣을지 결정. 디폴트로 전체 객체를 넣는다.

    SQLite의 경우 999가 최대이므로 999로 설정된다.

  • update_conflicts: True로 설정하는 경우 충돌이 발생하면 update_fields를 업데이트 하도록 한다.
    • 오라클은 지원하지 않는다.
    • PostgreSQL, SQLite의 경우 unique_fields를 넣어야 사용할 수 있다.
  • ignore_conflicts: PK를 설정하지 않는다.
    • DB가 지원하는 경우에만 사용 가능
    • MySQL, MariaDB에서는 사용 불가.

주의점

  • 장고 Model의 save(), clean()과 같은 기본 메서드를 사용하지 못한다. → DB에 직접 넣는 방식이기 때문에 기본 메서드를 지원하지 않는다.
  • multi-table 상속시 자식 모델에 대해 적용할 수 없다.

    multi-table inheritance: 추상 모델을 상속하는 것이 아닌 모델 그 자체를 상속하는 경우

  • 모델의 PK를 AutoField로 설정한 경우 특정 DB에서만 완전히 지원한다. → 현재 PostgreSQL, MariaDB 10.5+, and SQLite 3.35+ 에서만 지원하며 이외 DB에서는 PK가 설정되지 않는다.

성능 비교

적용 이전

  • 코드
    for d in data_list:
    		Example.objects.create(
    				...
    		).save()
  • django test → 1.399s 1
  • unittest → 13.0s 2
  • postman → API요청 시 4.71s 3

이후

  • 코드
    example_list = [Example( x ...) for x in data_list]
    Example.objects.bulk_create(example_list)
  • django test → 0.557s 4
  • unittest → 5.8s 5
  • postman→ API요청 시 2.53s 6

결과 요약

postman API응답 기준

초기4.7s
스케줄만 적용3.0s약 -1.7s
빌딩만 적용4.1s약 -0.6s
전체 적용2.5s약 -2.2s

결론

현재 프로그램 상 빌딩은 row가 1440으로 고정되어있다. 하지만 스케줄의 경우 3870이상의 row가 입력될 수 있으며 이에따른 성능 향상 폭은 더 커질 것으로 예상한다. 간단한 코드 한줄로 크게 성능이 개선될 수 있음을 경험했다. 또한 장고 공식문서에 친절히 나와있어 적용는데 어려움이 없었다. 공식 문서가 친절한 장고인 만큼 공식 문서를 적극적으로 사용하면 좋을 것 같다.

참고.

Django Documentation QuerySet API reference

0개의 댓글

관련 채용 정보