【发布时间】:2023-03-18 05:13:01
【问题描述】:
在我看来,在使用 sqlalchemy 时,经历创建表达式树然后再次从中创建查询的整个过程是浪费时间。除了偶尔的动态查询外,在应用程序的整个生命周期中几乎所有内容都完全相同(当然参数除外)。
有没有什么方法可以在创建查询后保存它并在以后使用不同的参数重复使用它?或者也许有一些内部机制已经做了类似的事情?
【问题讨论】:
标签: python caching sqlalchemy
在我看来,在使用 sqlalchemy 时,经历创建表达式树然后再次从中创建查询的整个过程是浪费时间。除了偶尔的动态查询外,在应用程序的整个生命周期中几乎所有内容都完全相同(当然参数除外)。
有没有什么方法可以在创建查询后保存它并在以后使用不同的参数重复使用它?或者也许有一些内部机制已经做了类似的事情?
【问题讨论】:
标签: python caching sqlalchemy
在我看来,在使用 sqlalchemy 时,经历创建表达式树然后再次从中创建查询的整个过程是浪费时间。
与应用程序的其余部分相比,您对浪费了多少时间有任何估计吗?在使您的程序更复杂之前,此处的分析非常重要。正如我经常注意到的,Reddit 每天提供超过 10 亿的页面浏览量,他们使用 SQLAlchemy Core 来查询他们的数据库,而我上次查看他们的代码时,他们并没有尝试优化这个过程——他们在上面构建了表达式树每次飞行并编译。但是,我们有一些用户已经确定他们的特定系统实际上受益于这些领域的优化。
我在这里写了一些关于性能分析的背景:How can I profile a SQLAlchemy powered application?
有没有什么方法可以在创建查询后保存它并在以后使用不同的参数重复使用它?或者也许有一些内部机制已经做了类似的事情?
有多种方法,具体取决于您使用的 API 以及您想要优化的区域。
呈现 SQL 有两个主要部分 - 可以说是表达式树的构造,然后是从表达式树中编译字符串。
可以重用树本身,如果使用 Core,则可以是 select() 构造,如果使用 ORM,则可以是 Query()。一个 select() 尤其没有任何相关联的东西,这会阻止它像你喜欢的那样经常被重用(对于 insert()、delete()、update() 等也是如此)。
在 ORM 中,Query 也可以通过 with_session() 方法用于不同的会话。这里的胜利并不多,因为Query() 每次调用时仍然会产生一个完整的select()。然而,正如我们将在下面看到的,有一个可以允许缓存的方法。
下一级优化涉及缓存实际呈现的 SQL 文本。这是一个需要多加注意的领域,因为我们生成的 SQL 是特定于目标后端的;还有一些极端情况,各种参数化会改变 SQL 本身(例如在 SQL Server 中使用“TOP N ROWS”,我们不能在那里使用绑定参数)。使用Connection 的execution_options() 方法提供SQL 字符串的缓存,该方法在其他一些地方也可用,通过向其发送字典或其他将缓存字符串的类似字典的对象来设置compiled_cache 功能语句的格式,以方言为关键字,构造的身份以及发送的参数。这个特性通常被 ORM 用于插入/更新/删除语句。
我在BakedQuery 发布了一个将compiled_cache 功能与Query 集成在一起的食谱。通过获取任何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()
它是实验性的,并不经常使用,但这正是您在这里所要求的。我建议您根据自己的需要对其进行定制,在使用时注意内存使用情况,并确保遵循它的工作原理。
【讨论】:
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
【讨论】: