Как загрузить огромный LOB Oracle с помощью cx_Oracle в системе с ограниченной памятью?

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

Вопрос

Я разрабатываю часть системы, в которой процессы ограничены примерно 350 МБ ОЗУ;мы используем 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-350 МБ, поэтому мы попробовали что-то вроде этого вместо того, чтобы читать его весь сразу:

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,5 ГБ).Почему 2000 байт?Согласно документам Oracle, dbms_lob.substr() сохраняет возвращаемое значение в формате RAW, размер которого ограничен 2000 байтами.

Есть ли способ сохранить dbms_lob.substr() приводит к увеличению объекта данных и чтению, возможно, нескольких мегабайт за раз?Как мне это сделать с помощью cx_Oracle?

Это было полезно?

Решение

Я думаю, что порядок аргументов в lob.read() в вашем коде обратный.Первый аргумент должен быть смещением, второй аргумент должен быть считываемой суммой.Это объяснило бы время O(n) и использование памяти.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top