メモリ制約付きシステムでCX_ORACLEを使用して巨大なOracle Lobをダウンロードする方法

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

質問

プロセスが約350MBのRAMに制限されているシステムの一部を開発しています。 CX_ORACLEを使用して、外部システムからファイルをダウンロードします。

外部システムはファイルをブロブとして保存します。

# ... 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()は、300~350MBを超えるファイルをヒットすると、MemoryErrorでは明らかに失敗するため、一度にそれを読む代わりにこのようなものを試してみました。

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()が撮影されていて、最終的にメモリ外の状態が得られ、のデータベースから引っ張っているかのように見えます。つまり、読み取りは、バッファがかなり小さい方があっても、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バイト? Oracle Docsによると、lob.read()はその戻り値をRAWに格納します。これは2000バイトに制限されています。

dbms_lob.substr()を保存できるような方法は、より大きなデータオブジェクトになり、一度に数メガバイトを読むことができますか? CX_ORACLEを使用するにはどうすればいいですか?

役に立ちましたか?

解決

lob.read()の引数順序があなたのコードで逆になっていると思います。最初の引数はオフセットである必要がありますが、2番目の引数は読み取り量です。これにより、O(n)時間とメモリの使用量について説明します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top