Wie lade ich ein riesiges Oracle LOB mit cx_Oracle auf ein speicherbeschränktes System herunter?

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

Frage

Ich entwickle einen Teil eines Systems, in dem Prozesse auf etwa 350 MB RAM begrenzt sind;wir verwenden cx_Oracle, um Dateien von einem externen System zur Verarbeitung herunterzuladen.

Das externe System speichert Dateien als BLOBs, und wir können sie auf diese Weise abrufen:

# ... 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 offensichtlich mit scheitern MemoryError wenn wir auf eine Datei stoßen, die größer als 300-350 MB ist, haben wir so etwas ausprobiert, anstatt 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 bekommen wir immer noch MemoryError nach mehreren Iterationen.Aus der Zeit lob.read() nimmt, und der Zustand, in dem wir nicht genügend Speicher haben, sieht so aus, als ob lob.read() zieht (chunk_size + read_size ) Bytes aus der Datenbank jedesmal.Das heißt, Lesevorgänge benötigen O (n) Zeit und O (n) Speicher, obwohl der Puffer etwas kleiner ist.

Um das zu umgehen, haben wir so etwas ausprobiert:

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 jeweils 2000 Bytes (argh) und dauert ewig (etwa zwei Stunden für eine 1,5-GB-Datei).Warum 2000 Bytes?Laut den Oracle-Dokumenten, dbms_lob.substr() speichert seinen Rückgabewert in einem RAW, der auf 2000 Byte begrenzt ist.

Gibt es eine Möglichkeit, wie ich das speichern kann dbms_lob.substr() ergibt ein größeres Datenobjekt und liest vielleicht ein paar Megabyte gleichzeitig?Wie mache ich das mit cx_Oracle?

War es hilfreich?

Lösung

Ich denke, dass die Argumentreihenfolge in lob.read() ist in Ihrem Code umgekehrt.Das erste Argument sollte der Offset sein, das zweite Argument sollte der zu lesende Betrag sein.Dies würde die O (n) -Zeit und die Speichernutzung erklären.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top