2010-09-13 7 views
9

SQLAlchemy के अनुसार, चुनिंदा बयानों को लूप के लिए iterables के रूप में माना जाता है। प्रभाव यह है कि एक चुनिंदा बयान जो बड़ी मात्रा में पंक्तियों को वापस करेगा, अत्यधिक स्मृति का उपयोग नहीं करता है।चुनिंदा वक्तव्य पर SQLAlchemy मेमोरी हॉग

मैं लग रहा है कि एक MySQL तालिका पर निम्नलिखित बयान:

for row in my_connections.execute(MyTable.__table__.select()): 
    yield row 

इसका अनुसरण करते हैं, जैसा कि मैंने उपलब्ध स्मृति अतिप्रवाह और इससे पहले कि पहली पंक्ति सामने आए है ताड़ना शुरू करने के लिए प्रतीत नहीं होता। मैं क्या गलत कर रहा हूं?

उत्तर

12

मूल MySQLdb कर्सर सर्वर से एक बार में संपूर्ण क्वेरी परिणाम प्राप्त करता है। यह बहुत सारी मेमोरी और समय का उपभोग कर सकता है। MySQLdb.cursors.SSCursor का उपयोग करें जब आप एक बड़ी क्वेरी बनाना चाहते हैं और एक समय में सर्वर से परिणाम खींचें।

इसलिए, connect_args={'cursorclass': MySQLdb.cursors.SSCursor} गुजर जब engine बनाने का प्रयास करें:

from sqlalchemy import create_engine, MetaData 
    import MySQLdb.cursors 
    engine = create_engine('mysql://root:[email protected]/e2', connect_args={'cursorclass': MySQLdb.cursors.SSCursor}) 
    meta = MetaData(engine, reflect=True) 
    conn = engine.connect() 
    rs = s.execution_options(stream_results=True).execute() 

देखें http://www.sqlalchemy.org/trac/ticket/1089


नोट SSCursor का उपयोग कर तालिका ताले कि लाने पूरा हो गया है जब तक। यह एक ही कनेक्शन का उपयोग कर अन्य कर्सर को प्रभावित करता है: उसी कनेक्शन से दो कर्सर समवर्ती रूप से तालिका से नहीं पढ़ सकते हैं।

हालांकि, अलग-अलग कनेक्शन से कर्सर एक ही तालिका से एक साथ पढ़ सकते हैं।

import MySQLdb 
import MySQLdb.cursors as cursors 
import threading 
import logging 
import config 

logger = logging.getLogger(__name__) 
query = 'SELECT * FROM huge_table LIMIT 200' 

def oursql_conn(): 
    import oursql 
    conn = oursql.connect(
     host=config.HOST, user=config.USER, passwd=config.PASS, 
     db=config.MYDB) 
    return conn 

def mysqldb_conn(): 
    conn = MySQLdb.connect(
     host=config.HOST, user=config.USER, 
     passwd=config.PASS, db=config.MYDB, 
     cursorclass=cursors.SSCursor) 
    return conn 

def two_cursors_one_conn(): 
    """Two SSCursors can not use one connection concurrently""" 
    def worker(conn): 
     cursor = conn.cursor() 
     cursor.execute(query) 
     for row in cursor: 
      logger.info(row) 

    conn = mysqldb_conn() 
    threads = [threading.Thread(target=worker, args=(conn,)) 
       for n in range(2)] 
    for t in threads: 
     t.daemon = True 
     t.start() 
     # Second thread may hang or raise OperationalError: 
     # File "/usr/lib/pymodules/python2.7/MySQLdb/cursors.py", line 289, in _fetch_row 
     # return self._result.fetch_row(size, self._fetch_type) 
     # OperationalError: (2013, 'Lost connection to MySQL server during query') 

    for t in threads: 
     t.join() 

def two_cursors_two_conn(): 
    """Two SSCursors from independent connections can use the same table concurrently"""  
    def worker(): 
     conn = mysqldb_conn()   
     cursor = conn.cursor() 
     cursor.execute(query) 
     for row in cursor: 
      logger.info(row) 

    threads = [threading.Thread(target=worker) for n in range(2)] 
    for t in threads: 
     t.daemon = True 
     t.start() 
    for t in threads: 
     t.join() 


logging.basicConfig(level=logging.DEBUG, 
        format='[%(asctime)s %(threadName)s] %(message)s', 
        datefmt='%H:%M:%S') 
two_cursors_one_conn() 
two_cursors_two_conn() 

ध्यान दें कि oursql अजगर के लिए MySQL बाइंडिंग का एक वैकल्पिक सेट है:

यहाँ कुछ समस्या का प्रदर्शन कोड है। oursql कर्सर सही सर्वर-साइड कर्सर हैं जो fetch rows lazily by default हैं। oursql इंस्टॉल करके, आप फांसी या एक अपवाद को ऊपर उठाने के बिना

conn = mysqldb_conn() 

को
conn = oursql_conn() 

तो two_cursors_one_conn() रन बदलते हैं।

+0

यह MySQL और yield_per के साथ मेरी मेमोरी समस्याओं को ठीक करता है। किसी भी विचार से ट्रैक पर जवाब क्यों कहता है कि यह "बेकार पर" है? – bcoughlan

+1

@bcoughlan: मैंने समसामयिक रूप से एसएसकर्सर्स का उपयोग करने की सीमा के कुछ कोड और चर्चा को जोड़ा है। – unutbu

+0

यह mysqldb के लिए हल होना चाहिए, क्या mysqlconnector के लिए एक समान विकल्प है, क्योंकि मुझे उस ड्राइवर का उपयोग कर एक ही समस्या का सामना करना पड़ रहा है। –