我正在開發一個系統的一部分,進程被限制在大約350MB的RAM;我們使用cx_Oracle從外部系統下載文件進行處理。如何在內存受限系統上使用cx_Oracle下載巨大的Oracle LOB?
外部系統存儲文件爲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個字節(哎呀),並採取永遠(有點像兩個小時一個1.5GB的文件)。爲什麼是2000字節?根據Oracle文檔,dbms_lob.substr()
將其返回值存儲在RAW中,限制爲2000字節。
有什麼方法可以將dbms_lob.substr()
結果存儲在一個更大的數據對象中,並且每次讀取的數據量可能幾個兆字節?我如何用cx_Oracle做到這一點?
哇,我簡直不敢相信那是錯的。 * facepalm *謝謝! –