【问题标题】:How to download huge Oracle LOB with cx_Oracle on memory constrained system?如何在内存受限的系统上使用 cx_Oracle 下载巨大的 Oracle LOB?
【发布时间】:2012-09-22 09:25:18
【问题描述】:

我正在开发一个系统的一部分,其中进程被限制为大约 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())

当我们遇到大于 300-350MB 的文件时,lob.read() 显然会以 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() 占用的时间到我们最终得到的内存不足情况,看起来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 文件来说大约需要两个小时)。为什么是 2000 字节?根据 Oracle 文档,dbms_lob.substr() 将其返回值存储在 RAW 中,限制为 2000 字节。

有什么方法可以将dbms_lob.substr() 结果存储在一个更大的数据对象中,并且一次读取几兆字节?如何使用 cx_Oracle 做到这一点?

【问题讨论】:

    标签: python oracle blob cx-oracle lob


    【解决方案1】:

    我认为 lob.read() 中的参数顺序在您的代码中是相反的。第一个参数应该是偏移量,第二个参数应该是要读取的数量。这将解释 O(n) 时间和内存使用情况。

    【讨论】:

    • 哇,我不敢相信这是错的。 facepalm 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多