在大量查询结果的循环中,更新操作花费了奇怪的时间

Posted

技术标签:

【中文标题】在大量查询结果的循环中,更新操作花费了奇怪的时间【英文标题】:in the loop of large quantity query result, update operation costs strange time 【发布时间】:2014-12-10 14:03:55 【问题描述】:

当我查询大量记录时,然后循环结果。 如果我更新一条记录,会花费很多时间。

_users = db.session.query(WxUser).limit(10000).all()
for _user in _users:
    t1 = time()
    db.session.query(WxUser).filter_by(id=_user.id).update(dict(sex=WxUser.Sex.MALE))
    db.session.commit()
    t2 = time()
    print t2 - t1

输出:

0.242075920105
15.5323040485
16.6957418919

提交操作花费时间超过正常。 打开“SQLALCHEMY_ECHO”时,显示 SQLAlchemy 按 id 查询每条记录。

它是怎么发生的?

【问题讨论】:

你在问为什么 SQLAlchemy 会更新每条记录吗?因为您正在查询您的 foo 循环中的每个 WxUser 并更新其性别。在您的情况下,您正在对数据库进行 10001 次查询。 查询本身看起来非常缓慢。你为什么不尝试像db.session.query(WxUser).limit(10000).update(dict(sex=WxUser.Sex.MALE)) 这样更简单的方法,即使那样也会花费很多时间。 【参考方案1】:

https://bitbucket.org/zzzeek/sqlalchemy/issue/3270/in-the-loop-of-large-quantity-query-result

我问 SQLAlchemy 的作者。 他给出了答案:

两种技术将解决所花费的时间。

    轮流在 Python 中评估对象以查看它们是否符合条件:

    s.query(WxUser).filter_by(id=_user.id).update(dict(data='M'), synchronize_session=False)

文档:http://docs.sqlalchemy.org/en/rel_0_9/orm/query.html?highlight=query.update#sqlalchemy.orm.query.Query.update.params.synchronize_session

    在调用 update() 之前不要使会话中的所有 10000 个对象过期,这表明为了使上述 synchronize_session='evaulate' 起作用,它必须命中每个 WxUser 对象并评估它们的“id”,这需要从数据库中重新加载它们:

    会话 = 会话(expire_on_commit=False)

文档:http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html#committing

【讨论】:

以上是关于在大量查询结果的循环中,更新操作花费了奇怪的时间的主要内容,如果未能解决你的问题,请参考以下文章

Postgres 更新极慢

奇怪的分析结果:肯定会弹出非瓶颈方法

循环渲染的 Django 模板查询花费了太多时间

SQL-query 在代码中比直接查询 db 花费更长的时间

MySQL查询性能优化

MySQL查询性能优化