2012-05-14 16 views
6

मैं आरईएफ अखंडता नियमों के साथ डेटाबेस में कई 10k रिकॉर्ड डाल रहा हूं। डेटा की कुछ पंक्तियां दुर्भाग्यवश डुप्लिकेट हैं (उनमें वे डेटाबेस में पहले से मौजूद हैं)। इसे सम्मिलित करने से पहले डेटाबेस में प्रत्येक पंक्ति के अस्तित्व की जांच करना बहुत महंगा होगा, इसलिए मैं एसक्यूएलकेमी द्वारा फेंकने वाले इंटीग्रिटीएरर अपवादों को संभालने, त्रुटि लॉगिंग करने और फिर जारी रखने के लिए आगे बढ़ना चाहता हूं।SQLAlchemy IntegrityError और थोक डेटा आयात

मेरे कोड कुछ इस तरह दिखेगा:

# establish connection to db etc. 

tbl = obtain_binding_to_sqlalchemy_orm() 
datarows = load_rows_to_import() 

try: 
    conn.execute(tbl.insert(), datarows) 
except IntegrityError as ie: 
    # eat error and keep going 
except Exception as e: 
    # do something else 

(छुपा हुआ) धारणा मैं ऊपर बना रहा हूँ कि SQLAlchemy एक सौदे में अनेक निवेशन रोलिंग नहीं है। अगर मेरी धारणा गलत है तो इसका मतलब है कि यदि एक ईमानदारी त्रुटि होती है, तो शेष डालने को छोड़ दिया जाता है। क्या कोई पुष्टि कर सकता है कि उपरोक्त छद्म कोड "पैटर्न" अपेक्षित काम करेगा - या क्या मैं इंटीग्रिटीइर अपवादों को फेंकने के परिणामस्वरूप डेटा खोना समाप्त कर दूंगा?

इसके अलावा, अगर किसी को ऐसा करने का बेहतर विचार है, तो मुझे इसे सुनना होगा।

उत्तर

1

यह इस तरह काम कर सकता है, अगर आपने पहले कोई लेनदेन शुरू नहीं किया था, क्योंकि इस मामले में sqlalchemy का autocommit feature किक होगा। लेकिन आपको लिंक में वर्णित रूप से स्पष्ट रूप से सेट करना चाहिए।

0

मुझे इस समस्या का भी सामना करना पड़ा जब मैं एक तालिका में डेटा आयात करने के लिए ASCII डेटा फ़ाइलों को पार्स कर रहा था। समस्या यह है कि मैं सहजतापूर्वक और सहजता से एसक्यूएलकेमी को अद्वितीय डेटा की अनुमति देते हुए डुप्लिकेट पंक्तियों को छोड़ना चाहता था। या यह मामला हो सकता है कि वर्तमान SQL इंजन के कारण एक यादृच्छिक त्रुटि को पंक्ति के साथ फेंक दिया जाता है, जैसे यूनिकोड तारों की अनुमति नहीं है।

हालांकि, यह व्यवहार SQL इंटरफ़ेस की परिभाषा के दायरे से बाहर है। एसक्यूएल एपीआई, और इसलिए SQLAlchemy केवल लेनदेन को समझता है और करता है, और इस चुनिंदा व्यवहार के लिए खाता नहीं है। इसके अलावा, यह autocommit सुविधा पर निर्भर होने के लिए खतरनाक लगता है, क्योंकि सम्मिलन के बाद प्रविष्टि रोकता है, शेष डेटा छोड़ देता है।

मेरा समाधान (जो मुझे यकीन नहीं है कि यह सबसे सुंदर है या नहीं) लूप, पकड़ और लॉग अपवादों में प्रत्येक पंक्ति को संसाधित करना और अंत में परिवर्तन करना है।

मान लीजिए कि आपने किसी भी तरह सूचियों की सूची में डेटा हासिल किया है, यानी पंक्तियों की सूची जो स्तंभ मानों की सूचियां हैं। तो फिर तुम एक पाश में प्रत्येक पंक्ति पढ़ें:

# Python 3.5 
from sqlalchemy import Table, create_engine 
import logging 

# Create the engine 
# Create the table 
# Parse the data file and save data in `rows` 

conn = engine.connect() 
trans = conn.begin() # Disables autocommit 

exceptions = {} 
totalRows = 0 
importedRows = 0 

ins = table.insert() 

for currentRowIdx, cols in enumerate(rows): 
    try: 
     conn.execute(ins.values(cols)) # try to insert the column values 
     importedRows += 1 

    except Exception as e: 
     exc_name = type(e).__name__ # save the exception name 
     if not exc_name in exceptions: 
      exceptions[exc_name] = [] 
     exceptions[exc_name].append(currentRowIdx) 

    totalRows += 1 

for key, val in exceptions.items(): 
    logging.warning("%d out of %d lines were not imported due to %s."%(len(val), totalRows, key)) 

logging.info("%d rows were imported."%(importedRows)) 

trans.commit() # Commit at the very end 
conn.close() 

आदेश में इस ऑपरेशन में गति को अधिकतम करने के लिए, आपको autocommit अक्षम करना चाहिए। मैं SQLite के साथ इस कोड का उपयोग कर रहा हूं और यह अभी भी sqlite3 का उपयोग करके मेरे पुराने संस्करण की तुलना में 3-5 गुना धीमा है, यहां तक ​​कि स्वतः से अक्षम अक्षम भी है। (जिस कारण से मैंने स्क्लाक्लेमी को पोर्ट किया था, वह इसे MySQL के साथ उपयोग करने में सक्षम था।)

यह इस अर्थ में सबसे सुंदर समाधान नहीं है कि यह SQLite के लिए प्रत्यक्ष इंटरफ़ेस जितना तेज़ नहीं है। अगर मैं कोड को प्रोफाइल करता हूं और निकट भविष्य में बाधा पाता हूं, तो मैं इस उत्तर को समाधान के साथ अपडेट कर दूंगा।

संबंधित मुद्दे