2012-10-01 17 views
6

मैं एक ऐसे सिस्टम का विकास कर रहा हूं जहां प्रक्रिया लगभग 350 एमबी रैम तक सीमित है; हम प्रसंस्करण के लिए बाहरी सिस्टम से फ़ाइलों को डाउनलोड करने के लिए cx_Oracle का उपयोग करते हैं।स्मृति अवरोध प्रणाली पर cx_Oracle के साथ विशाल ओरेकल LOB को कैसे डाउनलोड करें?

BLOBs के रूप में बाहरी प्रणाली दुकानों फ़ाइलों, और हम उन्हें कुछ इस तरह कर रही हड़पने कर सकते हैं:

# ... 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()) 

जब हम एक फ़ाइल 300-350MB से भी बड़ा हिट lob.read() जाहिर MemoryError साथ विफल हो जाएगा, तो हम है

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) 

दुर्भाग्य से, हम अभी भी कई पुनरावृत्तियों के बाद MemoryError मिलती है: कुछ इस तरह के बजाय इसे एक बार में सभी को पढ़ने की कोशिश की। उस समय से lob.read() ले रहा है, और अंततः स्मृति की स्थिति हमें मिलती है, ऐसा लगता है कि lob.read() डेटाबेस डेटाबेस से प्रत्येक बार खींच रहा है (chunk_size + read_size) बाइट्स खींच रहा है। यही है, पढ़ता है ओ (एन) समय और ओ (एन) स्मृति ले रहा है, भले ही बफर काफी छोटा है।

इस हल करने के लिए, हम कोशिश की है कुछ की तरह:

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

यह एक समय में 2000 बाइट (अरे) खींचती है, और हमेशा के लिए (एक 1.5GB फ़ाइल के लिए दो घंटे की तरह कुछ) लेता है। 2000 बाइट क्यों? ओरेकल दस्तावेज़ों के मुताबिक, dbms_lob.substr() एक रॉ में अपना रिटर्न वैल्यू स्टोर करता है, जो 2000 बाइट तक सीमित है।

क्या कोई तरीका है कि मैं dbms_lob.substr() परिणामों को एक बड़ी डेटा ऑब्जेक्ट में संग्रहीत कर सकता हूं और एक समय में शायद कुछ मेगाबाइट पढ़ सकता हूं? मैं cx_Oracle के साथ ऐसा कैसे करूं?

उत्तर

1

मुझे लगता है कि lob.read() में तर्क आदेश आपके कोड में उलट दिया गया है। पहला तर्क ऑफ़सेट होना चाहिए, दूसरा तर्क पढ़ने की राशि होनी चाहिए। यह ओ (एन) समय और स्मृति उपयोग की व्याख्या करेगा।

+0

वाह, मुझे विश्वास नहीं है कि यह क्या गलत था। * चेहरे * धन्यवाद! –