我正在尝试使用 SQLAlchemy 的bulk_save_objects方法一次更新大量对象(大约 1000-1500)。
下面是代码的简化版本。真正的用例还包括对象的有条件创建,这就是为什么我不使用bulk_update_mappings.
对于每个对象,可以修改多个列。为了将所有更新批处理为一个查询,我使用update_changed_only=False. 我认为这没有缺点,因为无论如何所有对象都被修改了。
代码:
import random
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session
import logging
logging.basicConfig()
logger = logging.getLogger('sqlalchemy.engine')
logger.setLevel(logging.DEBUG)
# init sqlalchemy
engine = create_engine('sqlite://')
session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)
session = Session()
Base = declarative_base()
# simple test model
class Foo(Base):
__tablename__ = 'test_foo'
id = Column(Integer, primary_key=True, autoincrement=True)
a = Column(String, default='')
b = Column(String, default='')
c = Column(String, default='')
# recreate database and sample data
Base.metadata.drop_all(bind=engine)
Base.metadata.create_all(bind=engine)
items = [
Foo() for _ in range(1000)
]
session.add_all(items)
session.commit()
# query all items
items = session.query(Foo).all()
# update some items
for item in items:
if random.random() < 0.5:
item.a += 'a'
if random.random() < 0.5:
item.b += 'b'
if random.random() < 0.5:
item.c += 'c'
# save the objects
session.bulk_save_objects(items, update_changed_only=False)
# ... do something more
# commit the transaction
session.commit()
Run Code Online (Sandbox Code Playgroud)
预期行为:
更新在单个查询中执行。
INFO:sqlalchemy.engine.base.Engine:UPDATE test_foo SET a=?, b=?, c=? WHERE test_foo.id = ?
INFO:sqlalchemy.engine.base.Engine:(('a', 'b', 'c', 1), ('a', 'b', 'c', 2), ('a', '', '', 3), ('a', '', '', 4), ('a', '', '', 5), ('', '', 'c', 6), ('a', 'b', '', 7), ('', '', 'c', 8) ... displaying 10 of 1000 total bound parameter sets ... ('', 'b', '', 999), ('a', 'b', 'c', 1000))
Run Code Online (Sandbox Code Playgroud)
实际行为:
更新在单个语句中执行,然后再次作为稍微分组的更新语句执行。
SQLAlchemy 版本:
SQLAlchemy==1.2.2
Run Code Online (Sandbox Code Playgroud)
题:
我该怎么做才能避免查询运行两次?