Welcome! 🙋‍♂️ View more

Engineering 💻/DB

[PostgreSQL] Python에서 다중 행을 Insert하는 다양한 방법과 비교

DeepFlame 2022. 2. 10. 19:00

🤔 Python으로 DB에 데이터를 입력할 때, 다중 행을 입력하는 경우가 많을 것이다. 이를 어떻게 실행해야 가장 빠르게 입력할 수 있을까?

😀 이러한 고민에 3가지 방법을 실행해봤고, 각 방법이 시간이 어떻게 차이나는 지 공유해보고자 한다.

 

먼저 입력할 데이터와 DB를 연결하자.

  1. 사용될 데이터는 10만개의 행과 3개의 열을 가진 Integer 데이터를 사용할 것이다. 
  2. DB는 PostgreSQL로 구축한 DB를 활용할 것이다.
import time
import psycopg2

N = 100000
data = [(i,i,i) for i in range(N)]
print('data length: ', len(data)) #10만개의 행

db = psycopg2.connect(host='localhost', dbname='test', user='postgres', password='postgres', port=5432)
cursor = db.cursor()

 

 

1. 반복문 활용


sql = "INSERT INTO public.inserttest VALUES (%s,%s,%s);"

start_time = time.time()
for row in data:
    try:
        cursor.execute(sql, row)
    except Exception as e:
        print("Insert Error: ", e)

db.commit()
print("%s: %.5f secs" % ("Taken Time", time.time() - start_time))

for문을 활용한 방법이다. 시간은 모두 입력하는데, 약 6.59초 걸린다.

이를 SQL 문으로 풀어쓰자면 아래와 같다.

INSERT INTO public.inserttest VALUES (0,0,0)
INSERT INTO public.inserttest VALUES (1,1,1)
INSERT INTO public.inserttest VALUES (2,2,2)
INSERT INTO public.inserttest VALUES (3,3,3)
INSERT INTO public.inserttest VALUES (4,4,4);

 

 

2. Executemany 함수 활용


sql = "INSERT INTO public.inserttest VALUES (%s,%s,%s);"

start_time = time.time()
try:
    cursor.executemany(sql, data)
except Exception as e:
    print("Insert Error: ", e)

db.commit()
print("%s: %.5f secs" % ("Taken Time", time.time() - start_time))

반복문을 제거하고, executemany 함수를 사용해서 좀 더 코드 가독성이 올라간 모습니다. 하지만 소모되는 시간은 유의미하게 다르진 않은 것으로 보인다. 

 

🤔 하지만 아래 블로그를 확인해보면 유의미하게 시간이 단축된 것을 확인할 수 있는데, 필자의 경우는 그렇지 않았다. 나중에 좀 더 살펴보아야할 문제이다.

https://blog.actorsfit.com/a?ID=01750-ec0f0ded-771d-4b06-a47f-7adb203e72c2 

 

 

3. mogrify 함수 사용


args_str = ", ".join([cursor.mogrify('(%s,%s,%s)', row).decode('utf-8') for row in data])
sql = "INSERT INTO public.inserttest VALUES {data};".format(data=args_str)

start_time = time.time()
try:
    cursor.execute(sql)
except Exception as e:
    print("Insert Error: ", e)

db.commit()
print("%s: %.5f secs" % ("Taken Time", time.time() - start_time))

🔥 시간이 다이나믹하게 줄었다! 100,000 개의 행 기준으로 10배 가까이 시간이 절약된 셈이다.

🤔 왜 그럴까? 그 이유가 명시되어 있는 문서는 없지만, 추측해보자면 3번 방법에서는 INSERT문 한 번에 모든 데이터가 입력되어 트랜잭션 횟수가 유의미하게 줄어든다. 이것이 시간이 줄어든 이유가 아닌가 추측된다.

INSERT INTO public.inserttest VALUES 
		(0,0,0), (1,1,1), (2,2,2), (3,3,3), (4,4,4);

 

 

결론


Insert 문에서는 mogrify 함수를 사용하는 것이 가장 속도가 빠르다!

  반복문 사용 Executemany 사용 mogrify 사용
소요 시간 6.592 초 5.925 초 0.652 초