Ich entwickle einen Teil eines Systems, in dem Prozesse auf etwa 350 MB RAM beschränkt sind; Wir verwenden cx_Oracle, um Dateien von einem externen System zur Verarbeitung herunterzuladen.Wie lade ich riesige Oracle LOB mit Cx_Oracle auf Speicher-Constrained-System?
das externe System speichert Dateien als BLOBs, und wir können sie so etwas wie dies greifen tun:
# ... 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()
wird natürlich mit MemoryError
fehlschlagen, wenn wir eine Datei größer als 300-350MB getroffen, so wir haben so etwas wie dies versucht stattdessen alles auf einmal zu lesen:
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)
Leider haben wir noch MemoryError
nach mehreren Iterationen erhalten. Von der Zeit lob.read()
nimmt, und die Out-of-Memory-Bedingung, die wir schließlich bekommen, sieht es aus, als ob lob.read()
zieht (chunk_size + read_size) Bytes aus der Datenbank jedes Mal. Das heißt, Lesevorgänge benötigen O (n) Zeit und O (n) Speicher, obwohl der Puffer ziemlich viel kleiner ist.
Um dies zu umgehen, haben wir versucht, so etwas wie:
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])
Dies zieht 2000 Byte (argh) zu einem Zeitpunkt, und dauert ewig (so etwas wie zwei Stunden für eine 1,5 GB-Datei). Warum 2000 Bytes? Laut Oracle-Dokumentation speichert dbms_lob.substr()
seinen Rückgabewert in einem RAW, der auf 2000 Byte begrenzt ist.
Gibt es eine Möglichkeit, die dbms_lob.substr()
Ergebnisse in einem größeren Datenobjekt speichern und vielleicht ein paar Megabytes gleichzeitig lesen? Wie mache ich das mit cx_Oracle?
Wow, ich kann nicht glauben, dass das was falsch war. * facepalm * Danke! –