python - 大量调用 SQLAlchemy 的 InstanceState 类的 expire 方法

标签 python mysql orm sqlalchemy innodb

我正在使用 11 个并行进程执行数据处理任务,每个计算的结果都使用 SQLAlchemy 的 ORM 记录在 MySQL 数据库的 InnoDB 表中。然而,处理时间比预期要长。如果我分析这些并行进程之一的执行情况,我可以看到大约 30% 的时间花费在 InstanceState 类的 expire 方法上,该方法被调用... 292,957,736 次!

计算执行 17,106 次迭代的循环,并且每次迭代执行一次提交。在配置文件中,我看到提交方法被称为 17,868,这似乎处于良好的数量级(761 补充提交可能来自周围代码的其他部分)。但是,我不太清楚该过期方法的作用以及为什么应该多次调用它。是在每次提交时在表的每一行上调用它还是什么?它看起来有点像,因为 if 17,106^2 == 292,615,236... 这种行为正常吗?对于在这种情况下如何做得更好,有什么食谱或建议吗?确切的代码有点复杂[它在 __computeForEvent(...) method of this file 中] 但是,SQLAlchemy 部分在概念上与此等效:

for i in range(17106):
    propagations = []
    for i in range(19):
        propagations.append(Propagation(...))
    session.add_all(propagations)
    session.commit()

其中 Propagation 是 Base 子类。 任何有关如何加快速度并避免expire(...) 调用爆炸式增长的建议将不胜感激。

最佳答案

对expire()的292M调用表明,当调用commit()时,内存中存在这么多对象,这实际上是一个令人难以置信的巨大数字。

消除这些过期调用的一种直接方法就是转 expire_on_commit为假:

sess = Session(expire_on_commit=False)

解决这个问题的一种更微妙的方法,但这需要更多的小心,就是不保留内存中的所有这些对象,如果我们这样做的话:

for i in range(17106):
    session.add_all([Propagation() for i in range(19)])
    session.commit()

如果 Propagation() 对象列表在没有引用循环的情况下没有被强引用,假设 cPython 它们将在取消引用时被垃圾收集,并且不会受到 commit() 内过期调用的影响。

还有一种策略可能只是将 commit() 延迟到循环之后,而不是使用lush() 一次处理每组项目。这样,大多数对象将在到达 commit() 时被垃圾回收。

不过,expire_on_commit 仍然是解决此问题的最直接方法。

关于python - 大量调用 SQLAlchemy 的 InstanceState 类的 expire 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20575692/

相关文章:

python - 为什么我的重新训练模型的准确性很差?

python - 从类中返回 subprocess.Popen 的输出

database - 自适应数据库

java - jpql 不加载 Blob

java - hibernate 缩小延迟加载集合范围

Python将字符串拆分为下一个句号标点符号

python - 使用 AppEngine 的 StringProperty 上的 "BadValueError: Filtering on Text properties is not supported"

php - Left Join 1 table to multiple tables in MYSQL

mysql - 使用现有行中的数据插入行

mysql - Django ORM。 Django如何知道新创建记录的自增pk