С SQLAlchemy ест оперативной памяти
Я пытаюсь импортировать некоторые XML-данные в мою базу данных MySQL после обработки ее с помощью Python. Чтобы все было просто, я делаю все это из одного скрипта, который использует SQLAlchemy для доступа к моей базе данных.
XML-файл имеет около 80 000 записей, и я обрабатываю его с помощью xml.etree.cElementTree
' s iterparse
метод и удалить узлы после их использования, чтобы сохранить использование памяти около 20 Мб.
как только я включаю SQLAlchemy и начинаю добавлять вещи в базу данных, использование моей памяти увеличивается на около 10 МБ в секунду, пока скрипт не исчерпает всю мою память, и ОС не убьет его.
вот в основном, как выглядит мой код:
index = 0
for element in iterate_xml():
...
index += 1
session.add(Model(**data))
if index % 1000 == 0:
session.flush()
session.commit()
Я не уверен, что еще попробовать. Периодическое .flush()
и .commit()
помогите немного, но они не исправляют проблему.
является ли SQLAlchemy не правильным инструментом для этой задачи?
я настраиваю SQLAlchemy следующим образом:
Base = declarative_base()
engine = create_engine(config.SQLALCHEMY_DATABASE_URI, echo=False)
Session = sessionmaker(bind=engine, autoflush=False, expire_on_commit=False)
session = Session()
и мой стол выглядит это:
columns = []
for name, datatype in structure.iteritems():
if isinstance(datatype, int):
datatype = String(datatype or 20)
column = Column(name, datatype)
columns.append(column)
metadata = MetaData(bind=engine)
table = Table('table_name', metadata,
Column('id', Integer, primary_key=True),
*columns
)
metadata.drop_all(engine)
metadata.create_all(engine)
class MyTable(Base):
__tablename__ = 'table_name'
__table_args__ = {
'autoload': True,
'autoload_with': engine
}
structure
- это словарь, который сопоставляет имена столбцов типам данных (он генерируется из XML):
structure = {
'column_name': SQLAlchemyDataType,
...
}
1 ответов
вот версия кода, доступная только для SQLAlchemy. Тестирование в 0.7 и 0.8, это не утечка памяти, что не удивительно для меня, потому что у нас есть более десятка тестов при непрерывной интеграции, чтобы гарантировать, что ничего не утечка во многих сценариях. Поэтому первый шаг-подтвердить, что этот сценарий не протекает для вас, а затем попытаться выяснить, какие изменения между этим сценарием и вашим, чтобы создать тестовый случай, который фактически показывает утечку памяти.
from sqlalchemy import Column, String, Integer, create_engine
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Model(Base):
__tablename__ = "a"
id = Column(Integer, primary_key=True)
data = Column(String)
e = create_engine("sqlite:///somefile.db")
Base.metadata.create_all(e)
session = Session(e)
for index in xrange(10000000):
session.add(Model(data="data %d" % index))
if index % 1000 == 0:
print "flushing... %d" % index
session.flush()
session.commit()
важно отметить конечно, те проблемы, где SQLAlchemy просочилась память в прошлом. Вот недавняя история исправленных утечек:
0.7.8 - самые последние. Утечка, исправленная здесь, произошла только при использовании: 1. расширения C, 2. драйвер pyodbc, во время определенных операций выборки результата (не все из них)
0.6.6 - "десятичный" процессор результатов в расширениях C имел утечку.
0.6.6 - расширение SQLSoup было определено как имеющее потенциальную утечку, если используется для выбора строки определенным образом (SQLSoup теперь это собственный проект)
0.5.5-исправлена потенциальная утечка памяти, когда объекты будут распакованы и помещены обратно в сеанс
0.5.4-основные улучшения использования памяти сеанса были сделаны. Вы определенно хотите быть далеко позади этой версии.