본문 바로가기
C.W.K.
Stream
Lesson 04 of 10 · published

executemany — 빠른 bulk 연산

~10 min · python, bulk, executemany, performance

Level 0Scout
0 XP0/80 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

루프를 Python이 아니라 C에서 돌려

executemany는 SQL statement 하나와 parameter tuple을 순회할 수 있는 것 하나를 받아. 그러면 드라이버가 C 쪽에서 루프를 돌면서 준비해둔 statement를 재사용해. 대량으로 넣을 때는 Python for 루프에서 row마다 execute를 부르는 것보다 훨씬 빨라. transaction 하나와 짝지으면 궁합도 자연스럽고.

규칙은 셋이야.

  • row를 100개 이상 쓸 거면 언제나 이걸 써.
  • with conn:으로 transaction 안에 넣어.
  • 덩치가 아주 크면 1천에서 1만 row씩 잘라. 메모리와 락 잡는 시간을 적당히 유지하려고.
Tip: executemany와 transaction의 조합이 대개 'insert가 느리게 느껴진다'와 'insert가 공짜처럼 느껴진다'를 가르는 선이야. SQLite가 느리다는 제보의 가장 흔한 원인이 transaction을 안 걸어서거든.

Code

Chunk로 잘라 돌리는 executemany·python
import sqlite3, itertools

def chunks(iterable, n):
    it = iter(iterable)
    while True:
        batch = list(itertools.islice(it, n))
        if not batch:
            return
        yield batch

conn = sqlite3.connect('demo.db')
conn.execute('PRAGMA journal_mode = WAL')

rows = ((f'u{i}@x.com', f'user{i}') for i in range(100_000))

for batch in chunks(rows, 5_000):
    with conn:
        conn.executemany('INSERT INTO users(email, username) VALUES (?, ?)', batch)

External links

Exercise

row 50,000개를 넣는 방식을 네 가지로 재봐. execute를 autocommit 루프로 도는 것, execute를 transaction 하나 안에서 도는 것, executemany를 한 번에 크게 부르는 것, executemany를 5,000개씩 잘라 chunk마다 transaction을 거는 것. 시간을 찍거나 그래프로 그리고, 왜 이런 차이가 나는지 설명해봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.