대량 데이터를 insert, update할 때 sqlalchemy에서 제공하는 add, add_all 등을 사용하는 것보다 빠른 방법이 있다
ORM은 기본적으로 고성능 bulk insert용이 아니다. 이것이 sqlalchemy가 core 기능을 제공하는 이유다

methods

bulk_save_objectsf()

객체 리스트를 대량 저장한다
객체 타입이 다르면 타입별 그룹으로 나뉘기 때문에 객체 리스트의 원소가 동일 타입이면 좋다

s = Session()
objects = [
    User(name="u1"),
    User(name="u2"),
    User(name="u3")
]
s.bulk_save_objects(objects)

bulk_save_objects()는 메서드명처럼 객체를 대량 저장한다. 이것과 다르게 bulk_insert_mappings(), bulk_update_mappings()는 dict list를 받는다. 개인적으로 메서드명이 bulk_insert_mappings가 아니라 bulk_insert_dicts였으면 더 좋았을 것 같다.

bulk_insert_mappings()

s.bulk_insert_mappings(User,
  [dict(name="u1"), dict(name="u2"), dict(name="u3")]
)

bulk_update_mappings()

s.bulk_update_mappings(User,
  [dict(name="u1"), dict(name="u2"), dict(name="u3")]
)

core

engine.execute(
  Customer.__table__.insert(),
  [{"name": 'NAME ' + str(i)} for i in xrange(n)]
)

batch speed comparison

  1. sqlalchemy core 를 사용하는 게 빠르다

  2. bulk_insert_mappings()가 model 객체 생성 후 attribute에 값 할당해서 commit하는 것보다 10배 이상 빠르다
    그러므로 add_all()보다 bulk_xxx_xxx() 메서드를 사용하는 게 효율적이다

  3. add_all()은 내부적으로 for문 사용하므로 느리다

속도 빠른 순
core > bulk_insert_mappings > bulk_save_objects > add_all

bulk 연산은 성능 이득을 위해 session 에서 하는 동작을 생략한다. 기본적으로 PK같은 default 값을 넣지 않는다.

속도 비교

1개의 댓글

comment-user-thumbnail
2023년 2월 7일

bulk_insert_mappings 결과를 받아보고 싶으면 어떻게 해야할까요?

답글 달기