我正在启动一个新应用程序,并考虑使用ORM,尤其是SQLAlchemy。
假设我的数据库中有一列“ foo”,我想增加它。在直通sqlite中,这很容易:
db = sqlite3.connect('mydata.sqlitedb') cur = db.cursor() cur.execute('update table stuff set foo = foo + 1')
我弄清楚了SQLAlchemy SQL-builder等效项:
engine = sqlalchemy.create_engine('sqlite:///mydata.sqlitedb') md = sqlalchemy.MetaData(engine) table = sqlalchemy.Table('stuff', md, autoload=True) upd = table.update(values={table.c.foo:table.c.foo+1}) engine.execute(upd)
这稍微慢一点,但是没有太多。
这是我对SQLAlchemy ORM方法的最佳猜测:
# snip definition of Stuff class made using declarative_base # snip creation of session object for c in session.query(Stuff): c.foo = c.foo + 1 session.flush() session.commit()
这样做是正确的,但所需的时间是其他两种方法的不到50倍。我认为这是因为它必须先将所有数据带入内存,然后才能使用它。
有什么方法可以使用SQLAlchemy的ORM生成高效的SQL?还是使用其他任何Python ORM?还是我应该回到手工编写SQL?
SQLAlchemy的ORM旨在与SQL层一起使用,而不是将其隐藏。但是,在同一事务中使用ORM和普通SQL时,您必须牢记一两件事。基本上,从一方面讲,仅当您从会话中清除更改时,ORM数据修改才会命中数据库。另一方面,SQL数据操作语句不会影响会话中的对象。
所以如果你说
for c in session.query(Stuff).all(): c.foo = c.foo+1 session.commit()
它会按照说的去做,从数据库中获取所有对象,修改所有对象,然后在需要时将更改刷新到数据库中,一行一行地更新。
相反,您应该这样做:
session.execute(update(stuff_table, values={stuff_table.c.foo: stuff_table.c.foo + 1})) session.commit()
这将像您期望的那样作为一个查询执行,并且因为至少默认会话配置在提交时使会话中的所有数据都失效,所以您没有任何过时的数据问题。
在即将发布的0.5系列中,您还可以使用以下方法进行更新:
session.query(Stuff).update({Stuff.foo: Stuff.foo + 1}) session.commit()
基本上,这将运行与上一片段相同的SQL语句,但还会选择更改的行并使会话中的所有过时数据过期。如果您知道更新后没有使用任何会话数据,则也可以synchronize_session=False将其添加到update语句中并摆脱该选择。
synchronize_session=False