메모리가 제한된 시스템에서 cx_Oracle을 사용하여 대규모 Oracle LOB를 다운로드하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com//questions/12674806

문제

저는 프로세스가 약 350MB의 RAM으로 제한되는 시스템의 일부를 개발 중입니다.처리를 위해 외부 시스템에서 파일을 다운로드하기 위해 cx_Oracle을 사용합니다.

외부 시스템은 파일을 BLOB으로 저장하며 다음과 같이 파일을 가져올 수 있습니다.

# ... set up Oracle connection, then
cursor.execute(u"""SELECT   filename, data, filesize
                   FROM    FILEDATA
                   WHERE   ID = :id""", id=the_one_you_wanted)
filename, lob, filesize = cursor.fetchone()

with open(filename, "w") as the_file:
    the_file.write(lob.read())

lob.read() 분명히 실패할 것이다 MemoryError 300-350MB보다 큰 파일에 도달하면 한꺼번에 읽는 대신 다음과 같이 시도했습니다.

read_size = 0
chunk_size = lob.getchunksize() * 100
while read_size < filesize:
    data = lob.read(chunk_size, read_size + 1)
    read_size += len(data)
    the_file.write(data)

불행하게도 우리는 여전히 MemoryError 여러 번의 반복 끝에.그때부터 lob.read() 복용하고 있으며 결국 메모리 부족 상태가 발생하는 것처럼 보입니다. lob.read() 데이터베이스에서 (chunk_size + read_size) 바이트를 가져오고 있습니다. 매번.즉, 버퍼가 상당히 작음에도 불구하고 읽기에는 O(n) 시간과 O(n) 메모리가 소요됩니다.

이 문제를 해결하기 위해 다음과 같은 방법을 시도했습니다.

read_size = 0
while read_size < filesize:
    q = u'''SELECT dbms_lob.substr(data, 2000, %s)
            FROM FILEDATA WHERE ID = :id''' % (read_bytes + 1)
    cursor.execute(q, id=filedataid[0])
    row = cursor.fetchone()
    read_bytes += len(row[0])
    the_file.write(row[0])

한 번에 2000바이트(argh)를 가져오며 시간이 오래 걸립니다(1.5GB 파일의 경우 2시간 정도).왜 2000바이트인가요?오라클 문서에 따르면, dbms_lob.substr() 반환 값을 2000바이트로 제한되는 RAW에 저장합니다.

저장할 수 있는 방법이 있나요? dbms_lob.substr() 더 큰 데이터 개체가 생성되고 한 번에 몇 메가바이트를 읽을 수 있습니까?cx_Oracle로 이 작업을 어떻게 수행합니까?

도움이 되었습니까?

해결책

코드에서 lob.read()의 인수 순서가 반대인 것 같습니다.첫 번째 인수는 오프셋이어야 하고, 두 번째 인수는 읽을 양이어야 합니다.이것은 O(n) 시간과 메모리 사용량을 설명합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top