Базовый курсор 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:zenoss@localhost/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 для Python.Курсоры oursql - это настоящие серверные курсоры, которые по умолчанию лениво извлекают строки .При установленном oursql
, если вы измените
conn = mysqldb_conn()
на
conn = oursql_conn()
, тогда two_cursors_one_conn()
будет работать без зависания или возникновения исключения.