在我看来,通过创建表达式树的整个过程,然后再次创建一个查询是使用sqlalchemy时浪费的时间。除了偶尔的动态查询外,在应用程序的整个生命周期中几乎所有内容都完全相同(当然除了参数)。
有没有办法在创建查询后保存查询,并在以后使用不同的参数重复使用?或者也许有一些内部机制已经做了类似的事情?
答案 0 :(得分:18)
在我看来,通过创建表达式树的整个过程,然后再次创建一个查询是使用sqlalchemy时浪费的时间。
与其他应用程序相比,您是否估计浪费了多少时间?在使程序更复杂之前,在此进行概要分析非常重要。正如我经常注意到的,Reddit每天提供超过10亿的页面浏览量,他们使用SQLAlchemy Core来查询他们的数据库,上次我查看他们的代码时他们没有尝试优化这个过程 - 他们构建表达式树飞行和编译每次。然而,我们已经让用户确定他们的特定系统实际上受益于这些领域的优化。
我在这里写了一些关于性能分析的背景知识:How can I profile a SQLAlchemy powered application?
有没有办法在创建查询后保存查询,并在以后使用不同的参数重复使用?或者也许有一些内部机制已经做了类似的事情?
有几种方法,具体取决于您使用的API以及您希望优化的区域。
渲染SQL有两个主要部分 - 可以说是表达式树的构造,然后是表达式树中字符串的编译。
树本身,如果使用Core,可以是select()构造,如果使用ORM,可以是Query(),可以重复使用。 select()特别没有任何与之关联的东西,阻止它像你喜欢的那样经常被重用(对于insert(),delete(),update()等都是如此)。
在ORM中,查询也可以使用with_session()方法与不同的会话一起使用。这里的胜利并不多,因为Query()
每次调用时仍会生成一个完整的select()
。但是,正如我们将在下面看到的那样,有一个配方可以允许缓存它。
下一级优化涉及缓存实际呈现的SQL文本。这是一个需要更多关注的领域,因为我们生成的SQL特定于目标后端;还有一些边缘情况,其中各种参数化改变了SQL本身(例如使用SQL Server的“TOP N ROWS”,我们不能在那里使用绑定参数)。使用Connection
compiled_cache
方法提供SQL字符串的缓存,该方法也可以在其他一些地方使用,通过向其发送字典或其他字典来设置compiled_cache
功能对象将缓存语句的字符串格式,键入方言,构造的标识和发送的参数。 ORM通常将此功能用于插入/更新/删除语句。
我发布的一个食谱将Query
功能与Query
集成在execution_options()。通过使用任何query.bake()
并说Session
,您现在可以使用任何q = s.query(Foo).filter(Foo.data==bindparam('foo')).bake()
for i in range(10):
result = q.from_session(s).params(foo='data 12').all()
运行该查询,只要您不在其上调用任何更多链式方法,它就应该使用缓存每次都是SQL字符串的形式:
{{1}}
它是实验性的,并不经常使用,但它正是你在这里所要求的。我建议你根据自己的需要定制它,在使用它时注意内存使用情况,并确保你遵循它的工作原理。
答案 1 :(得分:2)
SQLAlchemy 1.0引入了baked
扩展,这是一个专门用于缓存Query
对象的缓存。它缓存对象的构造和字符串编译步骤,以最大限度地减少Python解释器在重复查询上的开销。
官方文档:http://docs.sqlalchemy.org/en/latest/orm/extensions/baked.html
请注意,它不会缓存数据库返回的结果集。为此,您需要查看dogpile.cache
:
http://docs.sqlalchemy.org/en/latest/orm/examples.html#module-examples.dogpile_caching