Python 了解SQLAlchemy在对过期查询和更新进行迭代时的性能
我在SQLAlchemy中迭代一个查询并对行执行更新,结果发现性能出人意料地差,比我预期的慢了几个数量级。数据库大约有12K行。我最初的查询和循环如下所示:Python 了解SQLAlchemy在对过期查询和更新进行迭代时的性能,python,mysql,sqlalchemy,Python,Mysql,Sqlalchemy,我在SQLAlchemy中迭代一个查询并对行执行更新,结果发现性能出人意料地差,比我预期的慢了几个数量级。数据库大约有12K行。我最初的查询和循环如下所示: query_all = session.query(MasterImages).all() for record_counter, record in enumerate(query_all): # Some stuff happens here, set_id and set_index are defined sess
query_all = session.query(MasterImages).all()
for record_counter, record in enumerate(query_all):
# Some stuff happens here, set_id and set_index are defined
session.query(MasterImages).\
filter(MasterImages.id == record.id).\
update({'set_id':set_id, 'set_index':set_index})
if record_counter % 100 == 0:
session.commit()
print 'Updated {:,} records'.format(record_counter)
session.commit()
query_all = session.query(MasterImages.id, MasterImages.project_id,
MasterImages.visit, MasterImages.orbit,
MasterImages.drz_mode, MasterImages.cr_mode).all()
循环中的第一次迭代非常快,但在第一次提交后似乎会停止。我尝试了很多不同的方法,但都没有成功。然后,我尝试更改我的查询,以便它只选择我需要计算更新中使用的set\u id
和set\u index
值的字段,如下所示:
query_all = session.query(MasterImages).all()
for record_counter, record in enumerate(query_all):
# Some stuff happens here, set_id and set_index are defined
session.query(MasterImages).\
filter(MasterImages.id == record.id).\
update({'set_id':set_id, 'set_index':set_index})
if record_counter % 100 == 0:
session.commit()
print 'Updated {:,} records'.format(record_counter)
session.commit()
query_all = session.query(MasterImages.id, MasterImages.project_id,
MasterImages.visit, MasterImages.orbit,
MasterImages.drz_mode, MasterImages.cr_mode).all()
这产生了我期待的表现,在不到一分钟的时间里翻阅了所有记录。经过一段时间的思考,我认为我的问题是,在提交后的第一个查询中,由于我更新了一个字段(不必要地)在我迭代的查询中,该字段变成了一个过时的查询。我认为,这迫使Alchemy在每次提交后重新生成查询。通过从我迭代的查询中删除我正在更新的字段,我认为我能够使用相同的查询,从而提高了性能
我说的对吗?关机
启用提交时的expire\u时,SQLAlchemy会在.commit()之后将query\u中的所有对象都标记为过期(或您所说的“过时”)。过期意味着,下次尝试访问对象上的属性时,SQLAlchemy将发出SELECT以刷新对象。关闭expire\u on\u commit将阻止它这样做。expire\u on\u commit是一个选项,这样就不会破坏ORM的原始使用,所以如果您知道自己在做什么,就可以安全地将其关闭
您的修复之所以有效,是因为当您在query()中指定列(MasterImages.id等)而不是映射类(MasterImages)时,SQLAlchemy会向您返回一个普通的python元组,而不是映射类的实例。元组不提供ORM功能,即它不会过期,并且永远不会从数据库中重新提取自身。因此在提交时过期
是我可以进行的额外优化吗?什么时候以及什么时候不使用此功能的最佳实践是什么?另外,我在我的原始帖子中对陈旧查询的理解是否正确?有点像。SQLAlchemy将query\u all
中的所有对象标记为在.commit()
之后过期(或您所说的“过时”),而不是在.update()
之后。过期意味着下次尝试访问对象上的属性时,SQLAlchemy将发出SELECT
刷新对象。关闭在提交时过期将阻止它这样做expire\u on\u commit
是一个选项,这样就不会破坏ORM的原始使用,因此如果您知道自己在做什么,可以安全地将其关闭。我已经更新了问题,使用适当的术语“expired”而不是“stale”。但是,您能解释一下为什么在我更改迭代的查询时我的代码会加速吗?当您在query()
中指定列(MasterImages.id
等)而不是映射类(MasterImages
)时,SQLAlchemy会向您返回一个普通的python元组,而不是映射类的实例。元组不提供ORM特性,也就是说,它不会过期,也永远不会从数据库中重新获取自身。这非常有意义!请将您的评论添加到主要答案正文中,我将接受。