तो मुझे एक बड़ा डेटाबेस मिला है जिसे मैं एक बार में स्मृति में नहीं रख सकता। मुझे टेबल में प्रत्येक आइटम पर लूप करना है, इसे संसाधित करना है, और संसाधित डेटा को तालिका में किसी अन्य कॉलम में रखना है।क्या मुझे एक रिकॉर्डसेट पर लूप करने के लिए एकाधिक कर्सर ऑब्जेक्ट्स चाहिए और एक ही समय में अपडेट करें?
जबकि मैं अपने कर्सर पर लूपिंग कर रहा हूं, अगर मैं एक अद्यतन कथन चलाने की कोशिश करता हूं तो यह रिकॉर्डसेट को छोटा करता है (मुझे विश्वास है क्योंकि यह कर्सर ऑब्जेक्ट का पुन: उद्देश्य कर रहा है)।
सवाल:
अद्यतन बयान मुझे मूल का चयन करें बयान के ऊपर पाशन जारी रखने की अनुमति को चलाने के लिए एक दूसरे कर्सर वस्तु बनाने होगा?
क्या मुझे दूसरा कर्सर ऑब्जेक्ट रखने के लिए डेटाबेस से दूसरे कनेक्शन की आवश्यकता है, जो मुझे ऐसा करने की अनुमति देगा?
डेटाबेस के दो कनेक्शन, तालिका से एक पढ़ने, अन्य लेखन के जवाब देने के लिए sqlite कैसे प्रतिक्रिया देगा?
मेरे कोड (सरलीकृत):
select = """
SELECT id, unprocessed_content
FROM data_table
WHERE processed_content IS NULL
LIMIT 1000
"""
तो मैं क्या करना होगा:
recordset = data_manager.cursor.execute(select)
while recordset:
#do update stuff...
recordset = data_manager.cursor.execute(select)
import sqlite3
class DataManager():
""" Manages database (used below).
I cut this class way down to avoid confusion in the question.
"""
def __init__(self, db_path):
self.connection = sqlite3.connect(db_path)
self.connection.text_factory = str
self.cursor = self.connection.cursor()
def genRecordset(self, str_sql, subs=tuple()):
""" Generate records as tuples, for str_sql.
"""
self.cursor.execute(str_sql, subs)
for row in self.cursor:
yield row
select = """
SELECT id, unprocessed_content
FROM data_table
WHERE processed_content IS NULL
"""
update = """
UPDATE data_table
SET processed_content = ?
WHERE id = ?
"""
data_manager = DataManager(r'C:\myDatabase.db')
subs = []
for row in data_manager.genRecordset(str_sql):
id, unprocessed_content = row
processed_content = processContent(unprocessed_content)
subs.append((processed_content, id))
#every n records update the database (whenever I run out of memory)
if len(subs) >= 1000:
data_manager.cursor.executemany(update, subs)
data_manager.connection.commit()
subs = []
#update remaining records
if subs:
data_manager.cursor.executemany(update, subs)
data_manager.connection.commit()
अन्य विधि मैंने कोशिश की होने के लिए मेरी चयन कथन को संशोधित करने के लिए था
मेरे साथ समस्या यह थी कि मेरा वास्तविक चयन कथन में इसमें शामिल है और इसमें कुछ समय लगता है, इसलिए जॉइन को निष्पादित करना कि कई बार बहुत समय गहन है। मैं प्रक्रिया को तेज़ी से चुनने की कोशिश कर रहा हूं, फिर एक जनरेटर का उपयोग करके, इसलिए मुझे इसे स्मृति में रखना नहीं है।
समाधान:
ठीक है, तो मेरे पहले दो सवालों का जवाब है "नहीं" मेरे तीसरे प्रश्न के लिए, एक बार डेटाबेस में कनेक्शन बनने के बाद, यह पूरे डेटाबेस को लॉक कर देता है, इसलिए दूसरा कनेक्शन तब तक कुछ भी करने में सक्षम नहीं होगा जब तक कि पहला कनेक्शन बंद न हो जाए।
मुझे इसके लिए स्रोत कोड नहीं मिला, लेकिन अनुभवजन्य साक्ष्य से मुझे विश्वास है कि एक कनेक्शन केवल एक कर्सर ऑब्जेक्ट का उपयोग कर सकता है और अंतिम रन क्वेरी को प्राथमिकता दी जाती है। इसका मतलब यह है कि, जब मैं एक बार में एक पंक्ति उत्पन्न करने वाले चयनित रिकॉर्डसेट पर लूपिंग कर रहा हूं, जैसे ही मैं अपना पहला अपडेट स्टेटमेंट चलाता हूं, मेरा जनरेटर पंक्तियां उत्पन्न करना बंद कर देता है।
मेरा समाधान एक अस्थायी डेटाबेस बनाना है जिसे मैं ided के साथ processed_content चिपकाता हूं, ताकि मेरे पास प्रति कनेक्शन/कर्सर ऑब्जेक्ट हो और डेटाबेस के समय-समय पर अस्थायी डेटाबेस में डालने के दौरान चयनित रिकॉर्डसेट पर लूपिंग जारी रख सके। एक बार जब मैं अपने चुने हुए रिकॉर्डसेट के अंत तक पहुंच जाता हूं तो मैं डेटा को अस्थायी डेटाबेस में वापस मूल में स्थानांतरित करता हूं।
यदि कोई कनेक्शन/कर्सर ऑब्जेक्ट्स के बारे में निश्चित रूप से जानता है, तो मुझे एक टिप्पणी में बताएं।
मैंने डेटाबेस के साथ अपने दूसरे कर्सर ऑब्जेक्ट के साथ दूसरा कनेक्शन बनाने का प्रयास किया, लेकिन यह मिला, "sqlite3.OperationalError डेटाबेस बंद है "। क्या यह अस्थायी तालिका बनाकर बस मिल सकता है? – tgray
कारण मैंने पहले कनेक्शन/कर्सर की कोशिश की है क्योंकि अस्थायी तालिका 12 जीबी के डेटा के करीब होगी (प्रभावी रूप से मेरे डेटाबेस के आकार को प्रभावी ढंग से दोगुना कर देती है)। – tgray
अरघ, आप सही हैं - स्क्लाइट का लॉक डीबी-चौड़ा है! - (अस्थायी तालिका केवल एक बार और सभी के लिए शामिल होने में मदद करेगी, लेकिन फिर आपको चयन/सीमा का उपयोग करना होगा (दोनों अस्थायी अद्यतन करना और वास्तविक तालिका, या वास्तविक वृद्धि को अद्यतन करना और उसी वृद्धि से अस्थायी रूप से हटाना) - तेजी से नहीं लगता है, लेकिन मुझे विकल्प नहीं दिखते हैं। –