Pregunta

Estoy desarrollando parte de un sistema donde los procesos están limitados a unos menos 350 mb de RAM;utilizamos cx_Oracle para descargar archivos desde un sistema externo para su procesamiento.

El sistema externo almacena archivos Blob, y podemos agarrar a hacer algo como esto:

# ... 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 fallar con MemoryError cuando nos topamos con un archivo de más de 300-menos 350 mb, por lo que hemos probado algo como esto en lugar de leer todo de una 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)

Por desgracia, todavía podemos obtener MemoryError después de varias iteraciones.Desde el momento en que lob.read() es de tomar, y la condición de memoria que finalmente se consigue, parece como si lob.read() está tirando ( chunk_size + read_size ) bytes a partir de la base de datos cada vez.Es decir, las lecturas se toma O(n) tiempo y O(n) en la memoria, incluso a pesar de que el buffer es un poco más pequeño.

Para evitar esto, hemos probado 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])

Esta tira de 2000 bytes (argh) en un momento, y se la lleva para siempre (algo así como dos horas para un archivo de 1,5 GB).Por qué de 2000 bytes?Según el Oráculo de google docs, dbms_lob.substr() almacena su valor de retorno en una materia, la cual está limitada a 2000 bytes.

Hay alguna manera en la que puedo almacenar la dbms_lob.substr() resultados en el mayor objeto de datos y leer tal vez un par de megabytes por un tiempo?¿Cómo puedo hacer esto con cx_Oracle?

¿Fue útil?

Solución

Creo que el argumento de la orden en lob.read() se invierte en el código.El primer argumento debe ser el desplazamiento, el segundo argumento debe ser la cantidad a leer.Esto explicaría la O(n) tiempo y el uso de la memoria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top