SQLAlchemy中所有行的高效更新

Posted

技术标签:

【中文标题】SQLAlchemy中所有行的高效更新【英文标题】:Efficient Update of All Rows in SQLAlchemy 【发布时间】:2020-02-19 03:13:03 【问题描述】:

我目前正在尝试更新表中的所有行,方法是根据同一行中另一列 source_images 的值设置一列 images 的值。

for row in Cars.query.all():
    # Generate a list of strings
    images = [s for s in row.source_images if 'example.com/' in s]

    # Column 'images' being updated is a sqlalchemy.dialects.postgresql.ARRAY(Text())
    Cars.query.filter(Cars.id == row.id).update('images': images) 

db_session.commit()

问题:这似乎真的很慢,尤其是在应用于 100k+ 行时。有没有更有效的更新行的方法?

类似问题:

#1:这个问题涉及通过增加值来更新所有行。

模型类定义:cars.py

from sqlalchemy import *
from sqlalchemy.dialects import postgresql
from ..Base import Base

class Car(Base):
    __tablename__ = 'cars'
    id = Column(Integer, primary_key=True)
    images = Column(postgresql.ARRAY(Text))
    source_images = Column(postgresql.ARRAY(Text))

【问题讨论】:

【参考方案1】:

您可以将操作带到数据库,而不是单独获取和更新每一行:

from sqlalchemy import select, column, func

source_images = select([column('i')]).\
    select_from(func.unnest(Car.source_images).alias('i')).\
    where(column('i').contains('example.com/'))

source_images = func.array(source_images)

Car.query.update(Car.images: source_images,
                 synchronize_session=False)

相关子查询将源图像取消嵌套,选择符合条件的图像,ARRAY() constructor 形成新的图像数组。

您也可以使用array_agg():

source_images = select([func.array_agg(column('i'))]).\
    select_from(func.unnest(Car.source_images).alias('i')).\
    where(column('i').contains('example.com/'))

【讨论】:

在这台机器上,使用本地数据库,更新 500,000 行包含随机源图像数组的行大约需要 5 秒,其中包含“example.com/”且 P >= 10%。

以上是关于SQLAlchemy中所有行的高效更新的主要内容,如果未能解决你的问题,请参考以下文章

flask-sqlalchemy的使用

Flask-SQLAlchemy 学习总结

flask_sqlalchemy

SQlAlchemy的增删改查

在 SQLAlchemy 中以特定格式按日期分组

尝试连接数据库和 Web 容器时 SQLAlchemy 连接被拒绝