Django로 개발하던 중 API로 요청이 올 때마다 요청에 맞게 테이블의 값을 모두 delete
하고 다시 insert
해야하는 상황이 발생했다. DB를 최대한 유지하고 싶었으나 요구사항을 만족시키기 위해 어쩔수 없이 모두 지우고 다시 만들어야 했다.
로직에 맞게 값을 구하고 구한 값을 바탕으로 for문을 통해 반복하며 Model.object.create().save()
로 insert쿼리를 날리게 되었다. 그 결과 API조회 시 약 5초의 시간이 발생하게 되었고 이를 줄이고자 방법을 찾게 되었다.
객체 리스트를 통해 효율적으로 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
를 업데이트 하도록 한다.save(), clean()
과 같은 기본 메서드를 사용하지 못한다. → DB에 직접 넣는 방식이기 때문에 기본 메서드를 지원하지 않는다.multi-table inheritance: 추상 모델을 상속하는 것이 아닌 모델 그 자체를 상속하는 경우
PostgreSQL, MariaDB 10.5+, and SQLite 3.35+
에서만 지원하며 이외 DB에서는 PK가 설정되지 않는다.for d in data_list:
Example.objects.create(
...
).save()
example_list = [Example( x ...) for x in data_list]
Example.objects.bulk_create(example_list)
postman API응답 기준
초기 | 4.7s | |
---|---|---|
스케줄만 적용 | 3.0s | 약 -1.7s |
빌딩만 적용 | 4.1s | 약 -0.6s |
전체 적용 | 2.5s | 약 -2.2s |
현재 프로그램 상 빌딩은 row가 1440으로 고정되어있다. 하지만 스케줄의 경우 3870이상의 row가 입력될 수 있으며 이에따른 성능 향상 폭은 더 커질 것으로 예상한다. 간단한 코드 한줄로 크게 성능이 개선될 수 있음을 경험했다. 또한 장고 공식문서에 친절히 나와있어 적용는데 어려움이 없었다. 공식 문서가 친절한 장고인 만큼 공식 문서를 적극적으로 사용하면 좋을 것 같다.