Есть у меня проект, который начинался ещё с Django 1.4. Раз в час специальный management command парсит json-файл с примерно 200 000 записей и загружает их в базу. Естественно, это оооочень медленный процесс. Раньше его ускорению помогало ручное управление транзакцией: перед циклом транзакция начиналась и каждую 1000 записей коммитилась. Беда в том, что сейчас проект работает на 1.9, в котором такой способ больше не работает. В 1.9 есть декоратор и менеджер контекста transaction.atomic, который по понятным причинам в цикле неприменим, а пара transaction.set_autocommit(False) и transaction.commit() работает только на самых примитивных операциях, вроде последовательного создания в базе новых несвязанных записей. Не мой случай. Что делать? От ORM'а избавляться очень бы не хотелось.
менеджер контекста transaction.atomic, который по понятным причинам в цикле неприменим
По каким?
Написано
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
Roman Kitaev: как? Обернуть им тело цикла? Тогда разом будут коммититься 200 000 записей. Обернуть кусок кода в теле цикла? Тогда будет коммититься каждая запись. А мне надо чтобы 1000 записей разом, потом ещё 1000, потом ещё и так 200 раз.
Сергей Горностаев: Кстати, зачем вообще тебе понадобились транзакции здесь?
Написано
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
Roman Kitaev: внутри блока with atomic() цикл по всему объёму данных? Так там 200 000 элементов, то есть 200 000 итераций. И коммит будет только после завершения всех 200 000. А мне надо коммитить каждую 1000 отдельно.
Написано
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
Roman Kitaev: для того, чтобы ускорить загрузку данных.
def auto_transaction(): #37 секунд
for i in range(10000):
name="String number %s" % i
Record.objects.create(name=name)
@transaction.commit_manually
def manual_transaction(): #2.65 секунды
for i in range(10000):
name="String number %s" % i
Record.objects.create(name=name)
transaction.commit()
Написано
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
sim3x: компромиссное между скоростью и надёжностью.
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
Изменять данные по которым идёт итерация - очень плохая идея.
Написано
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
В каждой записи не просто строка или цифра. Там словарь, по которому создаются объекты, который в последствии записываются в базу. Сколько конкретно объектов в одной записи неизвестно. Взаимосвязи между ними тоже неизвестны.
Сергей Горностаев: Транзакции для этого юзать - не ок. Лучше bulk create в джанге.
Написано
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
Roman Kitaev: bulk create, как я уже сказал, мне не подходит из-за разветвлённости данных. А применение транзакций для ускорения - это старинный рецепт, который есть в каждой статье на тему orm performance.
Сергей Горностаев
@sergey-gornostaev Автор вопроса, куратор тега Django
Roman Kitaev: спасибо за то, что натолкнул меня на мысль. Я её развил. Разбиваю данные на куски и скармливаю потокам gevent, которые заливают их в базу в контексте транзакции.