使用 Django ORM 进行选择性事务管理
Posted
技术标签:
【中文标题】使用 Django ORM 进行选择性事务管理【英文标题】:Selective Transaction Management with Django ORM 【发布时间】:2012-02-13 08:08:14 【问题描述】:我正在尝试在 mysql 上使用 Django 的 ORM 设计一个批量数据导入任务。通常,我会简单地使用 LOAD DATA INFILE,但我批量导入的数据包含三个表的记录,并且其中一些记录可能已经存在,所以我必须检查预先存在的记录,创建或检索它们的 ID ,然后在创建或检索其他记录时使用此 ID。
默认情况下,导入速率为 0.8 行/秒。相当可怕。我设法通过在受影响的表上运行 DISABLE KEYS 将其提高到 1.5 行/秒,但由于我有几百万行,这仍然太慢了。
对于加快 Django 的 ORM 批量导入复杂的表关系,是否有任何一般性建议?
我正在考虑禁用 Django 的事务管理,以便将整个导入包装在一个事务中。但是,由于导入需要很长时间,因此导入过程会定期更新状态模型以报告完成百分比。如果我将整个导入包装在一个事务中,它将无法更新此状态记录。那么有没有什么方法可以只为一组特定的模型禁用事务管理,并且仍然允许它提交一个单独的模型?
我想做这样的事情:
from django.db import transaction
transaction.enter_transaction_management()
transaction.managed(True)
from myapp.models import Status, Data
status = Status.objects.get(id=123)
try:
data = magically_get_data_iter()
for row in data:
d,_ = Data.objects.get_or_create(**data.keys())
d.update(data)
d.save() # not actually visible in admin until the commit below
if not row.i % 100:
status.current_row = row.i
status.total_rows = row.total
# obviously doesn't work, but this should somehow actually commit
status.save(commit=True)
finally:
transaction.commit()
【问题讨论】:
【参考方案1】:我通过将批量更新的模型和存储状态记录的模型放在不同的数据库中,然后禁用对前一个数据库的事务管理来解决这个问题。
例如我上面的例子的简化:
django.db.transaction.enter_transaction_management(using='primary')
django.db.transaction.managed(True, using='primary')
i = 0
for record in records:
i += 1
r = PrimaryDBModel(**record)
r.save() # This will no be committed until the end.
if not i % 100:
SecondaryDBModel.update()
status = SecondaryDBModel(id=123)
status.current_row = i
status.save() # This will committed immediately.
django.db.transaction.commit(using='primary')
django.db.transaction.leave_transaction_management(using='primary')
【讨论】:
以上是关于使用 Django ORM 进行选择性事务管理的主要内容,如果未能解决你的问题,请参考以下文章
python 之 Django框架(orm单表查询orm多表查询聚合查询分组查询F查询 Q查询事务Django ORM执行原生SQL)