2013-05-14 73 views
2

在我看来,像经历创建表达式树的整个过程,然后再次创建查询是使用sqlalchemy时的浪费时间。除了偶尔的动态查询之外,几乎所有的应用程序在应用程序的整个生命周期中都会完全相同(除了参数)。如何重用/克隆sqlalchemy查询

有没有什么办法可以保存一个查询一旦创建并稍后重复使用不同的参数?或者也许有一些内部机制已经做了类似的事情?

回答

14

在我看来,经历创建表达式树并从中再次创建查询的整个过程似乎是使用sqlalchemy时的浪费时间。

与其他应用程序相比,您是否有估计浪费了多少时间?在使您的程序更复杂之前,对这里进行分析非常重要。我经常会注意到,Reddit每天的页面浏览量超过10亿次,他们使用SQLAlchemy Core来查询他们的数据库,而且最后一次查看他们的代码时,他们没有尝试优化这个过程 - 他们在表达式树上构建每一次飞行和编译。但是,我们有用户确定他们的具体系统实际上从这些领域的优化中受益。

我已经写了一些背景的剖析这里:How can I profile a SQLAlchemy powered application?

有什么办法,只是保存查询,一旦它的创建和使用不同的参数以后重新使用它?或者也许有一些内部机制已经做了类似的事情?

有几种方法,取决于您使用的API以及您想要优化的区域。

有渲染SQL两个主要部分 - 有表达式树的构建,可以这么说,然后从表达式树的字符串编译。

树本身,它可以是一个选择()构建体如果使用的ORM使用Core或查询()如果,可重复使用。 select()特别与它没有任何关联,可以防止它随时被重用(insert(),delete(),update()等)。

在ORM,查询也可以使用所述方法with_session()不同的会话中。这里的胜利不是那么多,因为每次调用它时Query()仍然会产生整个select()。然而,正如我们将在下面看到的,有一个可以允许缓存的配方。

下一级优化涉及到渲染的实际SQL文本的高速缓存。这是一个需要更多关注的领域,因为我们生成的SQL特定于目标后端;还有其他各种参数化会改变SQL本身的边缘情况(例如在SQL Server中使用“TOP N ROWS”,我们不能在那里使用绑定参数)。使用Connectionexecution_options()方法,这也是在其他一些地方使用提供的SQL字符串的缓存,通过发送一个词典或其他类似字典的对象,将缓存语句的字符串格式设置compiled_cache功能,锁定以方言,构造的身份以及发送的参数。该功能通常由ORM用于插入/更新/删除语句。

我发布了一个配方,它将compiled_cache功能与QueryBakedQuery相结合。通过采取任何Query,说query.bake(),你现在就可以运行该查询与任何Session只要你不叫上更多的链接的方法,它应该使用SQL字符串的缓存形式,每次:

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() 

这是实验性的,并不经常使用,但这正是你在这里要求的。我建议你根据自己的需求量身定制,在使用时注意内存的使用情况,并确保遵循它的工作原理。

+1

我希望我能给予好评此一百倍。这正是我正在编写的用于与原始代码进行比较的查询冻结界面。我的用例并不是应用程序的运行时,而是大量使用sqlalchemy(查询式)界面的测试。 sqlalchemy树操作总是出现在profiler输出之上,但我不想在检查是否有类似的东西之前编写我自己的“BakedQuery”版本 - 事实证明这里有:) – viraptor 2013-05-14 23:45:37

0

SQLAlchemy 1.0引入了baked扩展名,它是专门用于缓存对象的缓存。它缓存对象的构造和字符串编译步骤,以最大限度地减少重复查询中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