Domanda

Io sono in fase di sviluppo di un sistema in cui i processi sono limitato a circa 350MB di RAM;usiamo cx_Oracle il download di file da un sistema esterno per l'elaborazione.

L'esterno del sistema memorizza i file come Blob, e siamo in grado di afferrare loro facendo qualcosa di simile a questo:

# ... 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() ovviamente non con MemoryError quando abbiamo raggiunto un file di dimensioni superiori a 300-350 MB, così abbiamo provato qualcosa di simile, invece di leggerlo tutto in una volta:

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)

Purtroppo, dobbiamo ancora ottenere MemoryError dopo diverse iterazioni.Dal momento lob.read() sta prendendo, e la condizione di memoria otteniamo, sembra come se lob.read() sta tirando ( chunk_size + read_size ) byte dal database ogni volta.Che è, le letture sono di prendere tempo O(n) e O(n) memoria, anche se il buffer è un po ' più piccolo.

Per ovviare a questo, abbiamo cercato qualcosa di simile:

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

Questo tira 2000 byte (argh) alla volta, e prende sempre (qualcosa come due ore per un totale di 1,5 GB di file).Perché 2000 byte?Secondo Oracle docs, dbms_lob.substr() memorizza il valore di ritorno in RAW, che è limitata a 2000 byte.

C'è qualche modo per memorizzare il dbms_lob.substr() risultati in un più ampio oggetto di dati e di lettura forse un paio di megabyte in un momento?Come faccio a fare questo con cx_Oracle?

È stato utile?

Soluzione

Penso che l'ordine degli argomenti in lob.read() è invertito nel codice.Il primo argomento è l'offset, il secondo argomento dovrebbe essere la somma di leggere.Questo spiegherebbe il tempo O(n) e l'utilizzo della memoria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top