2010-09-24 14 views
13

में सभी पंक्तियों के माध्यम से पुन: प्रयास करने का सबसे अच्छा तरीका मैं अक्सर डीबी-टेबल की सभी पंक्तियों के माध्यम से पुनरावृत्ति करने के लिए छोटी पायथन स्क्रिप्ट लिखता हूं। उदाहरण के लिए सभी ग्राहकों को एक ईमेल भेजना।डीबी-टेबल

मैं मुझे आश्चर्य है कि अगर वहाँ इस कारण यह संभव है करने के लिए एक बेहतर तरीका है इस

conn = MySQLdb.connect(host = hst, user = usr, passwd = pw, db = db) 
cursor = conn.cursor() 
subscribers = cursor.execute("SELECT * FROM tbl_subscriber;") 

for subscriber in subscribers: 
... 

conn.close() 

तरह यह करना है कि मेरे कोड लोड स्मृति में पंक्तियों के हजारों।

मैंने सोचा कि यह LIMIT के साथ बेहतर किया जा सकता है। हो सकता है कि ऐसा ही कुछ:

"SELECT * FROM tbl_subscriber LIMIT %d,%d;" % (actualLimit,steps)  

क्या सबसे अच्छा तरीका यह करना है? आप यह कैसे करेंगे? "से ईमेल का चयन करें ..."

कि कम होगा:

उत्तर

32

जब तक आपके पास बीएलओबी नहीं है, हजारों पंक्तियों में कोई समस्या नहीं होनी चाहिए। क्या आप जानते हैं कि यह है?

इसके अलावा, क्यों

"SELECT * FROM tbl_subscriber LIMIT %d,%d;" % (actualLimit,steps) 

की तरह कुछ जब कर्सर किसी ऐसे तरीके से एसक्यूएल इंजेक्शन से बचा जाता है में आप के लिए प्रतिस्थापन कर देगा करके अपने और अपने पूरे परिवार पर शर्म की बात है लाने?

c.execute("SELECT * FROM tbl_subscriber LIMIT %i,%i;", (actualLimit,steps)) 
+1

+1 शेन सलाह है कि मैंने खुद को – pyfunc

+9

@pyfunc को अनदेखा किया। मैंने अपने जीवन में बहुत अधिक PHP लिखा है। मैं क्रिंग के बिना असुरक्षित कोड नहीं देख सकता। – aaronasterling

+1

आपकी सलाह के लिए धन्यवाद! मुझे नहीं पता था कि निष्पादित (...) एसक्यूएल इंजेक्शन से बचने में सक्षम है। हालांकि यह स्थानीय उपयोग के लिए एक स्क्रिप्ट है। – OemerA

2

सब हो सकता है आप * चयन की आवश्यकता नहीं है से ...

शायद यह काफी है तुम बस जैसे कुछ सामान पाने के लिए सबसे पहले वैसे भी स्मृति उपयोग की मात्रा :)

+0

ग्रेट प्वाइंट - 'चयन *' माना जाता है कि हानिकारक, या कम से कम आलसी प्रोग्रामिंग। – Piskvor

1

क्या आपके पास वास्तविक स्मृति समस्याएं हैं? एक कर्सर पर पुनरावृत्ति करते समय, परिणाम एक समय में प्राप्त किए जाते हैं (आपका डीबी-एपीआई कार्यान्वयन परिणाम पूर्व निर्धारित करने का निर्णय ले सकता है, लेकिन फिर यह प्रीफेच किए गए परिणामों की संख्या निर्धारित करने के लिए एक फ़ंक्शन पेश कर सकता है)।

6

libmysqlclient पर आधारित अधिकांश MySQL कनेक्टर प्रदर्शन परिणामों के लिए डिफ़ॉल्ट रूप से क्लाइंट मेमोरी में सभी परिणामों को बफर करेंगे (अनुमान के साथ आप बड़े परिणाम नहीं पढ़ेंगे)।

जब आपको MySQLdb में एक बड़ा परिणाम पढ़ने की आवश्यकता होती है तो आप पूरे बड़े परिणामों को बफर करने से बचने के लिए एक एसएससीसर का उपयोग कर सकते हैं।

http://mysql-python.sourceforge.net/MySQLdb.html#using-and-extending

SSCursor - A "server-side" cursor. Like Cursor but uses CursorUseResultMixIn. Use only if you are dealing with potentially large result sets.

यह जटिलताओं कि आप में से सावधान रहना चाहिए परिचय है।

>>> import MySQLdb 
>>> import MySQLdb.cursors 
>>> conn = MySQLdb.connect(read_default_file='~/.my.cnf') 
>>> curs = conn.cursor(MySQLdb.cursors.SSCursor) 
>>> curs.execute('SELECT * FROM big_table') 
18446744073709551615L 
>>> curs.fetchone() 
(1L, '2c57b425f0de896fcf5b2e2f28c93f66') 
>>> curs.execute('SELECT NOW()') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib64/python2.6/site-packages/MySQLdb/cursors.py", line 173, in execute 
    self.errorhandler(self, exc, value) 
    File "/usr/lib64/python2.6/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler 
    raise errorclass, errorvalue 
_mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now") 

इसका मतलब है आप हमेशा एक और जारी करने से पहले कर्सर से सब कुछ (और संभवत: कई resultsets) को पढ़ने के लिए - MySQLdb: आप कर्सर के सभी परिणामों को पढ़ा नहीं है, तो एक दूसरे क्वेरी एक ProgrammingError बढ़ा देंगे यह तुम्हारे लिए नहीं करेगा।

16

आपको क्वेरी को संशोधित करने की आवश्यकता नहीं है, आप fetchmany कर्सर की विधि का उपयोग कर सकते हैं।यहां बताया गया है कि मैं इसे कैसे करता हूं:

def fetchsome(cursor, some=1000): 
    fetch = cursor.fetchmany 
    while True: 
     rows = fetch(some) 
     if not rows: break 
     for row in rows: 
      yield row 

इस तरह से आप "चुन सकते हैं * tbl_subscriber से;" लेकिन आप एक समय में केवल कुछ लाएंगे।

+0

जब तक मैं गलत नहीं हूं, MySQL को आपकी पंक्तियों को पूरा करने वाली सभी पंक्तियां मिलेंगी, लेकिन जब तक आप पूछें तब तक उन्हें वापस भेज दें। उपरोक्त tbl_subscriber 'से 'SELECT * की आरंभिक क्वेरी अरबों पंक्तियों के साथ तालिका के लिए बहुत ही खराब प्रदर्शन करेगी। 'LIMIT' का अर्थ है MySQL केवल उन पंक्तियों की खोज करता है जो आपके अनुरोध को पूरा करते हैं और देख रहे हैं। Fetchmany पर दस्तावेज़ बहुत उपयोगी नहीं थे, तो कुछ जादू हो सकता है लेकिन मुझे शक है। –