python-oracledb executemany 메서드는 파이썬을 이용한 오라클 대량 데이터 처리에 필수입니다. 데이터베이스 애플리케이션 개발 시 대량의 데이터를 효율적으로 삽입, 수정 또는 삭제하는 능력은 시스템 성능에 지대한 영향을 미칩니다. python-oracledb
라이브러리는 이러한 요구사항을 충족시키기 위해 Cursor.executemany()
메서드와 Cursor.setinputsizes()
메서드를 제공하여 데이터 처리의 효율성을 극대화합니다.
1. python-oracledb executemany : 배치 실행을 통한 네트워크 오버헤드 최소화
관계형 데이터베이스 시스템과의 통신은 네트워크 왕복(round-trip) 비용이 발생합니다. SQL 문을 실행할 때마다 이 네트워크 비용이 항상 발생합니다.
대량 데이터를 처리하는 전통적인 방식은 Cursor.execute()
메서드를 반복하여 호출하는 것입니다. N건의 대량의 데이터를 처리할 때 N번의 네트워크 왕복이 발생하여 성능 저하의 주된 원인이 됩니다.
Cursor.executemany()
메서드는 하나의 SQL 문을 실행할 때 처리할 데이터를 한 번에 데이터베이스로 전송함으로써 단 한 번의 네트워크 왕복으로 다수의 작업을 완료하도록 설계되었습니다. 이는 네트워크 지연 시간과 데이터베이스 서버의 부하를 줄이고 전반적인 트랜잭션 처리 능력을 높여줍니다.
python-oracledb
executemany 활용 예시
10개의 컬럼을 가진 LargeTable
에 데이터를 삽입하는 예시를 통해 executemany()
의 효율성을 살펴보겠습니다.
예시의 LargeTable
은 다음과 같이 정의합니다.
CREATE TABLE LargeTable (
Col1 NUMBER,
Col2 VARCHAR2(50),
Col3 VARCHAR2(100),
Col4 VARCHAR2(200),
Col5 DATE
);
여러 건의 레코드를 삽입하는 파이썬 코드는 다음과 같습니다.
import oracledb
# 데이터베이스 연결 및 커서 생성 (예시)
connection = oracledb.connect(user="user", password="password", dsn="dsn")
cursor = connection.cursor()
data = [ (1, "Text A", "Longer text example A","Very long content A goes here", oracledb.Date(2025, 6, 2) ),
(2, "Text B", "Longer text example B","Very long content B goes here", oracledb.Date(2025, 6, 3) ),
(3, "Text C", "Longer text example C","Very long content C goes here", oracledb.Date(2025, 6, 4) )
]
# 단 한 번의 호출로 여러 레코드 삽입
cursor.executemany("""
INSERT INTO LargeTable (Col1, Col2, Col3, Col4, Col5)
VALUES (:1, :2, :3, :4, :5)
""", data)
connection.commit()
print(f"{cursor.rowcount} 개의 행이 삽입되었습니다.")
이 방식은 INSERT
문뿐만 아니라 UPDATE
, DELETE
, MERGE
와 같은 모든 DML(Data Manipulation Language) 문에 적용 가능하며, 대량의 데이터 조작 시 성능 최적화를 위한 필수적인 기법입니다.
2. setinputsizes()
: 메모리 버퍼 사전 할당을 통한 오버헤드 제거
python-oracledb executemany 는 네트워크 왕복 횟수를 줄여주지만, python-oracledb
가 데이터를 처리하는 방식 자체에서 발생하는 내부적인 오버헤드가 존재할 수 있습니다. 특히 가변 길이 데이터 타입(예: 문자열)을 처리할 때 이러한 현상이 두드러집니다.
python-oracledb
는 기본적으로 각 컬럼의 데이터 타입을 추정하고, 문자열/바이트 데이터의 경우 가장 긴 값이 나타날 때마다 동적으로 버퍼 크기를 조정합니다. 이러한 동적 메모리 재할당 및 데이터 복사 작업이 반복될수록 시스템 자원을 소모하고 성능 저하를 야기합니다.
Cursor.setinputsizes()
메서드는 이러한 오버헤드를 제거하기 위해 사용됩니다. 이 메서드를 통해 python-oracledb
에게 각 바인드 변수의 데이터 타입과 예상되는 최대 크기를 미리 알려줄 수 있습니다. 이는 SQL 실행 전에 충분한 크기의 메모리 버퍼를 할당하도록 하여 불필요한 재할당과 데이터 복사를 방지합니다.
setinputsizes()
의 활용 예시
위의 LargeTable
삽입 예시를 통해 setinputsizes()
의 효과를 확인해 보겠습니다.
import oracledb
connection = oracledb.connect(user="user", password="password", dsn="dsn")
cursor = connection.cursor()
data = [ (1, "Text A", "Longer text example A","Very long content A goes here", oracledb.Date(2025, 6, 2) ),
(2, "Text B", "Longer text example B","Very long content B goes here", oracledb.Date(2025, 6, 3) ),
(3, "Text C", "Longer text example C","Very long content C goes here", oracledb.Date(2025, 6, 4) )
]
# 5개 컬럼에 대한 setinputsizes 설정
# 각 인자는 SQL 문 바인드 변수 순서와 일치하며, 타입과 예상 최대 길이를 명시
cursor.setinputsizes(
None, # Col1: NUMBER
50, # Col2: VARCHAR2(50) - 최대 50자
100, # Col3: VARCHAR2(100) - 최대 200자
200, # Col4: VARCHAR2(200) - 최대 200자
None # Col5: DATE
)
cursor.executemany("""
INSERT INTO LargeTable (Col1, Col2, Col3, Col4, Col5)
VALUES (:1, :2, :3, :4, :5)
""", data)
connection.commit()
print(f"{cursor.rowcount} 개의 행이 삽입되었습니다.")
여기서 cursor.setinputsizes()
는 5개의 컬럼에 대해 각각의 특성에 맞춰 설정됩니다.
None
:NUMBER
,DATE
,TIMESTAMP
,CLOB
,BLOB
과 같이python-oracledb
가 이미 효율적으로 처리하거나 내부적으로 특수하게 관리하는 데이터 타입에 사용됩니다.- 정수 값:
VARCHAR2
와 같은 문자열 컬럼의 경우, 해당 컬럼에 저장될 최대 문자(character) 수를 정수로 지정합니다. 예를 들어,VARCHAR2(50)
컬럼에는50
을,VARCHAR2(200)
컬럼에는200
을 명시합니다. 한글과 같은 멀티바이트 문자도 문자 수 기준으로 지정하며,python-oracledb
가 내부적으로 바이트 수로 변환하여 적절한 버퍼를 할당합니다.
이러한 사전 할당을 통해, 데이터가 길어질 때마다 발생하는 동적인 버퍼 크기 조정 및 데이터 복사 오버헤드를 완전히 제거하여 성능을 최적화할 수 있습니다.
setinputsizes()
사용 시 고려사항
- 정확한 길이 지정: 문자열 컬럼의 경우, 실제 들어올 데이터의 최대 문자 수를 지정하는 것이 중요합니다.
- 과도한 크기 할당 지양: 필요한 크기보다 훨씬 큰 값을 지정하면 불필요한 메모리 낭비가 발생할 수 있습니다.
- 2GB 버퍼 제한: 할당되는 버퍼의 총 크기가 2GB를 초과할 경우
DPI-1015: array size of <n> is too large
오류가 발생할 수 있습니다. 이 경우,executemany()
호출 시 한 번에 처리하는 레코드의 수를 조정해야 합니다.
3. 정리
python-oracledb
의 Cursor.executemany()
및 Cursor.setinputsizes()
메서드는 대량 데이터를 처리하는 애플리케이션의 성능을 극대화하는 데 필수적인 도구입니다. executemany()
를 통한 네트워크 왕복 최소화와 setinputsizes()
를 통한 효율적인 메모리 버퍼 관리는 개발자가 고성능의 데이터베이스 연동 시스템을 구축하는 데 핵심적인 역할을 수행합니다. 이러한 최적화 기법을 적극적으로 활용하여 안정적이고 효율적인 데이터 처리 솔루션을 구현하시길 바랍니다.
참고 자료: python-oracledb 공식 문서 – Executing Batch Statements and Bulk Loading (이 글의 주요 참고 자료입니다.)