Pergunta

Eu estou desenvolvendo parte de um sistema onde os processos são limitadas a cerca de 350MB de memória RAM;nós usamos cx_Oracle para baixar arquivos a partir de um sistema externo para processamento.

O sistema externo armazena arquivos como BLOBs, e podemos agarrá-los a fazer algo como isso:

# ... 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() obviamente falhará com MemoryError quando nós batemos um arquivo maior do que 300-350MB, então nós tentamos algo como este, em vez de lê-lo todo de uma só vez:

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)

Infelizmente, temos ainda MemoryError depois de várias iterações.A partir do momento lob.read() está a tomar, e a falta de memória condição que, eventualmente, chegar, é como se lob.read() é puxando ( chunk_size + read_size ) bytes a partir do banco de dados cada vez.Isto é, lê-se está a tomar O(n) e S(n) de memória, mesmo que o buffer é um pouco menor.

Para contornar esse problema, nós tentamos algo como:

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])

Este puxa 2000 bytes (argh) de cada vez, e leva-o para sempre (algo como duas horas para um 1.5 GB de arquivos).Por 2000 bytes?De acordo com a Oracle, google docs, google dbms_lob.substr() armazena o valor de retorno de uma matéria-prima, que é limitada a 2000 bytes.

Existe alguma maneira eu posso armazenar o dbms_lob.substr() resulta em uma maior objeto de dados e leia talvez alguns megabytes de cada vez?Como posso fazer isso com cx_Oracle?

Foi útil?

Solução

Eu acho que o argumento de ordem em lob.read() é revertido em seu código.O primeiro argumento deve ser o deslocamento, o segundo argumento deve ser a quantidade de ler.Isso explicaria a O(n) e o tempo de uso de memória.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top