SqlAlchemy 2.0 中文文档(五十四)(2)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: SqlAlchemy 2.0 中文文档(五十四)

SqlAlchemy 2.0 中文文档(五十四)(1)https://developer.aliyun.com/article/1563177


性能

原文:docs.sqlalchemy.org/en/20/faq/performance.html

  • 为什么升级到 1.4 和/或 2.x 后我的应用程序变慢了?
  • 第一步 - 打开 SQL 日志记录并确认缓存是否正常工作
  • 第二步 - 确定哪些构造阻止启用缓存
  • 第三步 - 为给定的对象启用缓存和/或寻找替代方案
  • 如何对基于 SQLAlchemy 的应用程序进行性能分析?
  • 查询性能分析
  • 代码性能分析
  • 执行速度慢
  • 结果获取慢 - 核心
  • 结果获取慢 - ORM
  • 我正在使用 ORM 插入 400,000 行,速度非常慢!

为什么升级到 1.4 和/或 2.x 后我的应用程序变慢了?

SQLAlchemy 自 1.4 版本起包含一个 SQL 编译缓存功能,它将允许核心和 ORM SQL  构造缓存它们的字符串形式,以及用于从语句中获取结果的其他结构信息,当下次使用另一个结构上等同的构造时,可以跳过相对昂贵的字符串编译过程。这个系统依赖于为所有  SQL 构造实现的功能,包括诸如 Columnselect()TypeEngine 等对象,以生成完全代表它们状态的缓存键,至于它们对 SQL 编译过程产生的影响程度。

缓存系统使得 SQLAlchemy 1.4 及以上版本在将 SQL 构造重复转换为字符串所花费的时间方面比 SQLAlchemy 1.3  更高效。然而,这仅在为使用的方言和 SQL 构造启用缓存时才有效;如果没有启用缓存,则字符串编译通常类似于 SQLAlchemy  1.3,但在某些情况下速度略有下降。

然而,有一种情况是,如果 SQLAlchemy 的新缓存系统已被禁用(出于以下原因),则 ORM 的性能实际上可能明显低于 1.3 或其他之前的版本,这是由于 ORM 惰性加载器和对象刷新查询中缺乏缓存,而在 1.3 版本和更早版本中使用了现在已经过时的 BakedQuery 系统。如果应用程序在切换到 1.4 时看到了显著(30% 或更高)的性能下降(以操作完成所需的时间为度量),这可能是问题的根本原因,下面有缓解措施。

参见

SQL 编译缓存 - 缓存系统概述

对象将不生成缓存键,性能影响 - 关于不启用缓存的元素生成的警告的额外信息。

第一步 - 打开 SQL 记录并确认缓存是否起作用

在这里,我们想要使用引擎日志记录中描述的技术,查找带有[no key]指示器的语句,甚至是带有[dialect does not support caching]的语句。对于首次调用语句时成功参与缓存系统的 SQL 语句,我们会看到[generated in Xs]指示器,随后对于绝大多数后续语句会看到[cached since Xs ago]指示器。如果对于特定的 SELECT 语句主要存在[no key],或者如果由于[dialect does not support caching]完全禁用了缓存,这可能是导致性能严重下降的原因。

参见

使用日志估算缓存性能

第二步 - 确定哪些构造物阻止了缓存的启用

假设语句没有被缓存,在应用程序的日志中会及早发出警告(仅适用于 SQLAlchemy 1.4.28 及以上版本),指示不参与缓存的方言、TypeEngine 对象和 SQL 构造物。

对于诸如扩展TypeDecoratorUserDefinedType的用户定义数据类型,警告将如下所示:

sqlalchemy.ext.SAWarning: MyType will not produce a cache key because the
``cache_ok`` attribute is not set to True. This can have significant
performance implications including some performance degradations in
comparison to prior SQLAlchemy versions. Set this attribute to True if this
type object's state is safe to use in a cache key, or False to disable this
warning.

对于自定义和第三方 SQL 元素,例如那些使用自定义 SQL 构造和编译扩展中描述的技术构建的元素,这些警告会看起来像:

sqlalchemy.exc.SAWarning: Class MyClass will not make use of SQL
compilation caching as it does not set the 'inherit_cache' attribute to
``True``. This can have significant performance implications including some
performance degradations in comparison to prior SQLAlchemy versions. Set
this attribute to True if this object can make use of the cache key
generated by the superclass. Alternatively, this attribute may be set to
False which will disable this warning.

对于使用Dialect类层次结构的自定义和第三方方言,警告将如下所示:

sqlalchemy.exc.SAWarning: Dialect database:driver will not make use of SQL
compilation caching as it does not set the 'supports_statement_cache'
attribute to ``True``. This can have significant performance implications
including some performance degradations in comparison to prior SQLAlchemy
versions. Dialect maintainers should seek to set this attribute to True
after appropriate development and testing for SQLAlchemy 1.4 caching
support. Alternatively, this attribute may be set to False which will
disable this warning.

第三步 - 为给定对象启用缓存和/或寻求替代方案

缓存不足的缓解步骤包括:

  • ExternalType.cache_ok 设置为 True,用于所有继承自 TypeDecoratorUserDefinedType 的自定义类型,以及这些类型的子类,如 PickleType。仅当自定义类型不包含任何影响其渲染 SQL 的额外状态属性时才设置这个 属性
class MyCustomType(TypeDecorator):
    cache_ok = True
    impl = String
  • 如果使用的类型来自第三方库,请与该库的维护者联系,以便进行调整和发布。
    另请参阅
    ExternalType.cache_ok - 启用自定义数据类型缓存的要求背景。
  • 确保第三方方言将 Dialect.supports_statement_cache 设置为 True。这表明第三方方言的维护者确保其方言与 SQLAlchemy 1.4 或更高版本兼容,并且其方言不包含可能干扰缓存的编译特性。由于存在一些常见的编译模式可能会干扰缓存,因此方言维护者务必仔细检查和测试,调整任何与缓存不兼容的传统模式。
    另请参阅
    第三方方言的缓存 - 第三方方言参与 SQL 语句缓存的背景和示例。
  • 自定义 SQL 类,包括使用 自定义 SQL 构造和编译扩展 创建的所有 DQL / DML 构造,以及对象的临时子类,如 ColumnTable。对于简单子类,可以将 HasCacheKey.inherit_cache 属性设置为 True,该属性不包含影响 SQL 编译的子类特定状态信息。
    另请参阅
    为自定义构造启用缓存支持 - 应用 HasCacheKey.inherit_cache 属性的指南。

另请参阅

SQL 编译缓存 - 缓存系统概述

对象不会生成缓存键,性能影响 - 背景是在为特定结构和/或方言未启用缓存时发出警告的情况。## 如何分析一个使用 SQLAlchemy 的应用程序?

寻找性能问题通常涉及两种策略。一种是查询性能分析,另一种是代码性能分析。

查询性能分析

有时仅仅记录普通的 SQL(通过 python 的 logging 模块启用,或者通过create_engine()上的echo=True参数启用)就能让你了解到事情花费了多长时间。例如,如果在 SQL 操作之后记录一些内容,你会在日志中看到类似这样的内容:

17:37:48,325 INFO  [sqlalchemy.engine.base.Engine.0x...048c] SELECT ...
17:37:48,326 INFO  [sqlalchemy.engine.base.Engine.0x...048c] {<params>}
17:37:48,660 DEBUG [myapp.somemessage]

如果你在操作之后记录了myapp.somemessage,你就知道完成 SQL 部分花费了 334ms。

记录 SQL 还会说明是否发出了数十/数百个查询,这些查询可以更好地组织成更少的查询。当使用 SQLAlchemy ORM 时,“eager loading”特性提供了部分(contains_eager())或完全(joinedload()subqueryload())自动化此活动,但是没有 ORM 的“eager loading”通常意味着使用连接,以便结果可以在一个结果集中加载而不是随着更多深度的添加而增加查询的数量(即 r + r*r2 + r*r2*r3 …)

对于更长期的查询性能分析,或者实现应用程序端的“慢查询”监视器,可以使用事件来拦截游标执行,使用以下类似的配方:

from sqlalchemy import event
from sqlalchemy.engine import Engine
import time
import logging
logging.basicConfig()
logger = logging.getLogger("myapp.sqltime")
logger.setLevel(logging.DEBUG)
@event.listens_for(Engine, "before_cursor_execute")
def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
    conn.info.setdefault("query_start_time", []).append(time.time())
    logger.debug("Start Query: %s", statement)
@event.listens_for(Engine, "after_cursor_execute")
def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
    total = time.time() - conn.info["query_start_time"].pop(-1)
    logger.debug("Query Complete!")
    logger.debug("Total Time: %f", total)

在上述例子中,我们使用ConnectionEvents.before_cursor_execute()ConnectionEvents.after_cursor_execute()事件来在执行语句时建立拦截点。我们使用info字典在连接上附加一个计时器;我们在这里使用堆栈,因为偶尔会出现游标执行事件嵌套的情况。

代码性能分析

如果日志显示单个查询花费的时间太长,你需要分解在数据库内处理查询、通过网络发送结果、被 DBAPI 处理以及最终由 SQLAlchemy 的结果集和/或 ORM 层接收的时间。每个阶段都可能存在自己的瓶颈,具体取决于具体情况。

为此,您需要使用Python Profiling Module。以下是一个将分析集成到上下文管理器中的简单示例:

import cProfile
import io
import pstats
import contextlib
@contextlib.contextmanager
def profiled():
    pr = cProfile.Profile()
    pr.enable()
    yield
    pr.disable()
    s = io.StringIO()
    ps = pstats.Stats(pr, stream=s).sort_stats("cumulative")
    ps.print_stats()
    # uncomment this to see who's calling what
    # ps.print_callers()
    print(s.getvalue())

要对代码段进行分析:

with profiled():
    session.scalars(select(FooClass).where(FooClass.somevalue == 8)).all()

分析的输出可以用来了解时间花在哪里。分析输出的一部分如下所示:

13726 function calls (13042 primitive calls) in 0.014 seconds
Ordered by: cumulative time
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
222/21    0.001    0.000    0.011    0.001 lib/sqlalchemy/orm/loading.py:26(instances)
220/20    0.002    0.000    0.010    0.001 lib/sqlalchemy/orm/loading.py:327(_instance)
220/20    0.000    0.000    0.010    0.000 lib/sqlalchemy/orm/loading.py:284(populate_state)
   20    0.000    0.000    0.010    0.000 lib/sqlalchemy/orm/strategies.py:987(load_collection_from_subq)
   20    0.000    0.000    0.009    0.000 lib/sqlalchemy/orm/strategies.py:935(get)
    1    0.000    0.000    0.009    0.009 lib/sqlalchemy/orm/strategies.py:940(_load)
   21    0.000    0.000    0.008    0.000 lib/sqlalchemy/orm/strategies.py:942(<genexpr>)
    2    0.000    0.000    0.004    0.002 lib/sqlalchemy/orm/query.py:2400(__iter__)
    2    0.000    0.000    0.002    0.001 lib/sqlalchemy/orm/query.py:2414(_execute_and_instances)
    2    0.000    0.000    0.002    0.001 lib/sqlalchemy/engine/base.py:659(execute)
    2    0.000    0.000    0.002    0.001 lib/sqlalchemy/sql/elements.py:321(_execute_on_connection)
    2    0.000    0.000    0.002    0.001 lib/sqlalchemy/engine/base.py:788(_execute_clauseelement)
...

在上面的例子中,我们可以看到 instances() SQLAlchemy 函数被调用了 222 次(递归调用,外部调用 21 次),总共花费了 .011 秒来执行所有调用。

执行慢

这些调用的具体情况可以告诉我们时间花在哪里。例如,如果您看到时间花在 cursor.execute() 内部,例如针对 DBAPI:

2    0.102    0.102    0.204    0.102 {method 'execute' of 'sqlite3.Cursor' objects}

这将表示数据库需要很长时间才能开始返回结果,这意味着您的查询应该进行优化,可以通过添加索引或重构查询和/或底层架构来实现。对于这项任务,应该使用数据库后端提供的 EXPLAIN、SHOW PLAN 等系统来分析查询计划。

结果获取慢 - 核心

另一方面,如果你看到与获取行相关的许多调用,或者 fetchall() 的调用时间非常长,这可能意味着查询返回的行数超出了预期,或者获取行本身很慢。ORM 本身通常使用 fetchall() 来获取行(如果使用 Query.yield_per() 选项,则使用 fetchmany())。

通过在 DBAPI 级别使用 fetchall(),会导致调用非常慢,这可能表示行数过多:

2    0.300    0.600    0.300    0.600 {method 'fetchall' of 'sqlite3.Cursor' objects}

即使最终结果似乎没有很多行,但意外地大量行数可能是笛卡尔积的结果 - 当多组行未适当地连接在一起时。如果在复杂查询中使用了错误的Column 对象,从而引入了意外的额外 FROM 子句,那么使用 SQLAlchemy Core 或 ORM 查询往往很容易产生这种行为。

另一方面,在 DBAPI 级别使用 fetchall() 快速,但当 SQLAlchemy 的CursorResult 被要求执行 fetchall() 时却很慢,可能表示数据类型处理慢,比如 Unicode 转换等:

# the DBAPI cursor is fast...
2    0.020    0.040    0.020    0.040 {method 'fetchall' of 'sqlite3.Cursor' objects}
...
# but SQLAlchemy's result proxy is slow, this is type-level processing
2    0.100    0.200    0.100    0.200 lib/sqlalchemy/engine/result.py:778(fetchall)

在某些情况下,后端可能正在进行不需要的类型级处理。更具体地说,看到类型 API 中的慢调用是更好的指标 - 下面是使用此类类型时的情况:

from sqlalchemy import TypeDecorator
import time
class Foo(TypeDecorator):
    impl = String
    def process_result_value(self, value, thing):
        # intentionally add slowness for illustration purposes
        time.sleep(0.001)
        return value

这个有意慢操作的分析输出可以看起来像这样:

200    0.001    0.000    0.237    0.001 lib/sqlalchemy/sql/type_api.py:911(process)
200    0.001    0.000    0.236    0.001 test.py:28(process_result_value)
200    0.235    0.001    0.235    0.001 {time.sleep}

也就是说,我们在 type_api 系统中看到了许多昂贵的调用,而实际耗时的是 time.sleep() 调用。

请确保查阅方言文档以了解关于这个级别已知的性能调优建议的说明,特别是对于像 Oracle 这样的数据库。在这种情况下可能有一些关于确保数字精度或字符串处理的系统不需要在所有情况下都需要的系统。

在行提取性能受影响的更低级别可能还有更多的点;例如,如果花费的时间似乎集中在像 socket.receive() 这样的调用上,这可能表明除了实际的网络连接之外,一切都很快,而且花费了太多时间在数据在网络上传输上。

结果获取速度慢 - ORM

要检测 ORM 提取行的慢速(这是性能关注的最常见领域),调用如 populate_state()_instance() 将说明单个 ORM 对象的填充情况:

# the ORM calls _instance for each ORM-loaded row it sees, and
# populate_state for each ORM-loaded row that results in the population
# of an object's attributes
220/20    0.001    0.000    0.010    0.000 lib/sqlalchemy/orm/loading.py:327(_instance)
220/20    0.000    0.000    0.009    0.000 lib/sqlalchemy/orm/loading.py:284(populate_state)

ORM 将行转换为 ORM 映射对象的速度慢是这个操作的复杂性与 cPython 的开销的产物。减轻这种情况的常见策略包括:

  • 获取单个列而不是完整的实体,即:
select(User.id, User.name)
  • 而不是:
select(User)
  • 使用Bundle对象来组织基于列的结果:
u_b = Bundle("user", User.id, User.name)
a_b = Bundle("address", Address.id, Address.email)
for user, address in session.execute(select(u_b, a_b).join(User.addresses)):
    ...
  • 使用结果缓存 - 参见 Dogpile Caching 了解深入示例。
  • 考虑使用像 PyPy 这样的更快的解释器。

分析结果可能有点令人生畏,但经过一些实践后,它们就会变得非常容易阅读。

另请参阅

性能 - 一套具有捆绑式分析功能的性能演示。

我正在使用 ORM 插入 40 万行,但速度真的很慢!

ORM 插入的性质已经发生了变化,因为大多数包含的驱动程序在 SQLAlchemy 2.0 中都使用了 RETURNING 和  insertmanyvalues 支持。请参阅 除了 MySQL 外的所有后端现在都已实现优化的 ORM 批量插入 一节了解详情。

总的来说,SQLAlchemy 内置的驱动程序,除了 MySQL 外,现在应该提供非常快的 ORM 批量插入性能。

第三方驱动程序也可以选择使用一些小的代码更改来使用新的批量基础架构,假设他们的后端支持所需的语法。SQLAlchemy 开发人员鼓励第三方方言的用户发布关于这些驱动程序的问题,以便他们可以联系 SQLAlchemy 开发人员寻求帮助。

为什么我升级到 1.4 和/或 2.x 后我的应用程序变慢了?

截至版本 1.4,SQLAlchemy 包含一个 SQL 编译缓存设施,它允许核心和 ORM SQL  构造缓存它们的字符串形式,以及用于从语句中获取结果的其他结构信息,从而在下次使用另一个结构上等价的构造时跳过相对昂贵的字符串编译过程。该系统依赖于为所有  SQL 构造实现的功能,包括诸如Columnselect()TypeEngine对象等,以生成完全代表它们状态的缓存键,在影响 SQL 编译过程的程度上。

缓存系统使得 SQLAlchemy 1.4 及以上版本在将 SQL 构造反复转换为字符串方面比 SQLAlchemy 1.3  更高效。但是,这仅在启用了使用的方言和 SQL 构造的缓存时才有效;如果没有启用,字符串编译通常类似于 SQLAlchemy  1.3,某些情况下速度略有降低。

但是,有一种情况,即如果禁用了 SQLAlchemy 的新缓存系统(由于以下原因),则 ORM 的性能实际上可能显着低于 1.3 或其他先前版本,原因是在 1.3 和以前的版本中,ORM 惰性加载器和对象刷新查询中没有缓存,而是使用了现在已经过时的BakedQuery系统。如果应用程序在切换到 1.4 后性能显着下降(测量操作完成所需的时间为 30%或更高),则这可能是问题的主要原因,以下是缓解措施。

另请参阅

SQL 编译缓存 - 缓存系统概述

对象不会产生缓存键,性能影响 - 关于未启用缓存的元素生成警告的附加信息。

第一步 - 打开 SQL 日志并确认缓存是否正常工作

在这里,我们希望使用引擎日志记录中描述的技术,寻找带有[no key]指示器或甚至[dialect does not support caching]的语句。对于成功参与缓存系统的 SQL 语句,我们将看到首次调用语句时指示为[generated in Xs],对于绝大多数后续语句,将看到[cached since Xs ago]。如果特别是对于 SELECT 语句,或者如果由于[dialect does not support caching]而完全禁用缓存,则这可能是性能显著下降的原因。

另请参阅

使用日志估算缓存性能

第二步 - 确定是哪些构造物阻止了缓存的启用

假设语句未被缓存,应该会在应用程序日志的早期(仅适用于 SQLAlchemy 1.4.28 及以上版本)中发出警告,指示不参与缓存的方言、TypeEngine 对象和 SQL 构造。

对于像那些扩展 TypeDecoratorUserDefinedType 的用户定义数据类型,警告将如下所示:

sqlalchemy.ext.SAWarning: MyType will not produce a cache key because the
``cache_ok`` attribute is not set to True. This can have significant
performance implications including some performance degradations in
comparison to prior SQLAlchemy versions. Set this attribute to True if this
type object's state is safe to use in a cache key, or False to disable this
warning.

对于自定义和第三方 SQL 元素,比如那些使用 自定义 SQL 构造和编译扩展 中描述的技术构建的元素,这些警告将如下所示:

sqlalchemy.exc.SAWarning: Class MyClass will not make use of SQL
compilation caching as it does not set the 'inherit_cache' attribute to
``True``. This can have significant performance implications including some
performance degradations in comparison to prior SQLAlchemy versions. Set
this attribute to True if this object can make use of the cache key
generated by the superclass. Alternatively, this attribute may be set to
False which will disable this warning.

对于使用 Dialect 类层次结构的自定义和第三方方言,警告将如下所示:

sqlalchemy.exc.SAWarning: Dialect database:driver will not make use of SQL
compilation caching as it does not set the 'supports_statement_cache'
attribute to ``True``. This can have significant performance implications
including some performance degradations in comparison to prior SQLAlchemy
versions. Dialect maintainers should seek to set this attribute to True
after appropriate development and testing for SQLAlchemy 1.4 caching
support. Alternatively, this attribute may be set to False which will
disable this warning.

第三步 - 为给定对象启用缓存和/或寻求替代方案

缓解缓存不足的步骤包括:

  • 检查并设置 ExternalType.cache_okTrue,用于所有继承自 TypeDecoratorUserDefinedType 的自定义类型,以及这些类型的子类,如 PickleType。只有在自定义类型不包含影响其呈现 SQL 的其他状态属性时才设置此项:
class MyCustomType(TypeDecorator):
    cache_ok = True
    impl = String
  • 如果使用的类型来自第三方库,请与该库的维护者联系,以便进行调整和发布。
    另请参阅
    ExternalType.cache_ok - 关于启用自定义数据类型缓存的要求背景信息。
  • 确保第三方方言将 Dialect.supports_statement_cache 设置为 True。这表示第三方方言的维护者已确保其方言与  SQLAlchemy 1.4  或更高版本兼容,并且他们的方言不包含可能妨碍缓存的任何编译特性。由于有一些常见的编译模式实际上可能会干扰缓存,因此方言维护者必须仔细检查和测试此内容,并针对任何无法与缓存一起使用的旧模式进行调整。
    另请参见
    第三方方言的缓存 - 第三方方言参与 SQL 语句缓存的背景和示例。
  • 自定义 SQL 类,包括使用自定义 SQL 构造和编译扩展可能创建的所有 DQL / DML 构造,以及对象的临时子类,如ColumnTableHasCacheKey.inherit_cache 属性可以设置为 True,用于简单的子类,这些子类不包含影响 SQL 编译的子类特定状态信息。
    另请参见
    为自定义构造启用缓存支持 - 应用HasCacheKey.inherit_cache 属性的指南。

另请参见

SQL 编译缓存 - 缓存系统概述

对象不会生成缓存键,性能影响 - 在未为特定构造和/或方言启用缓存时发出警告的背景信息。

步骤一 - 打开 SQL 日志记录并确认缓存是否起作用

在这里,我们想要使用引擎日志记录中描述的技术,查找具有 [no key] 指示器或甚至 [dialect does not support caching] 的语句。当首次调用语句时,我们将看到参与缓存系统的 SQL 语句指示 [generated in Xs],然后对于绝大多数后续语句,指示为 [cached since Xs ago]。如果 [no key] 特别是对于 SELECT 语句普遍存在,或者如果由于 [dialect does not support caching] 而完全禁用缓存,这可能是导致性能严重下降的原因。

另请参见

使用日志估算缓存性能

第二步 - 确定哪些构造阻止了缓存的启用

假设语句未被缓存,则应在应用程序的日志中尽早发出警告(仅适用于 SQLAlchemy 1.4.28 及以上版本),指示不参与缓存的方言、TypeEngine 对象和 SQL 构造。

对于用户定义的数据类型,比如那些扩展了TypeDecoratorUserDefinedType的数据类型,警告信息如下:

sqlalchemy.ext.SAWarning: MyType will not produce a cache key because the
``cache_ok`` attribute is not set to True. This can have significant
performance implications including some performance degradations in
comparison to prior SQLAlchemy versions. Set this attribute to True if this
type object's state is safe to use in a cache key, or False to disable this
warning.

对于自定义和第三方 SQL 元素,例如使用 自定义 SQL 构造和编译扩展 中描述的技术构造的元素,这些警告信息如下:

sqlalchemy.exc.SAWarning: Class MyClass will not make use of SQL
compilation caching as it does not set the 'inherit_cache' attribute to
``True``. This can have significant performance implications including some
performance degradations in comparison to prior SQLAlchemy versions. Set
this attribute to True if this object can make use of the cache key
generated by the superclass. Alternatively, this attribute may be set to
False which will disable this warning.

对于使用 Dialect 类层次结构的自定义和第三方方言,警告信息如下:

sqlalchemy.exc.SAWarning: Dialect database:driver will not make use of SQL
compilation caching as it does not set the 'supports_statement_cache'
attribute to ``True``. This can have significant performance implications
including some performance degradations in comparison to prior SQLAlchemy
versions. Dialect maintainers should seek to set this attribute to True
after appropriate development and testing for SQLAlchemy 1.4 caching
support. Alternatively, this attribute may be set to False which will
disable this warning.

第三步 - 为给定的对象启用缓存和/或寻找替代方案

缓存缺失的缓解步骤包括:

  • 查看并设置 ExternalType.cache_ok,对于所有扩展自 TypeDecoratorUserDefinedType 的自定义类型,以及这些类型的子类,例如 PickleType。仅在自定义类型不包含影响其呈现 SQL 的其他状态属性时才设置此选项:
class MyCustomType(TypeDecorator):
    cache_ok = True
    impl = String
  • 如果使用的类型来自第三方库,请咨询该库的维护者,以便进行调整并发布。
    另请参阅
    ExternalType.cache_ok - 启用自定义数据类型缓存的要求背景。
  • 确保第三方方言设置Dialect.supports_statement_cacheTrue。这表示第三方方言的维护者已确保他们的方言与 SQLAlchemy 1.4 或更高版本兼容,并且他们的方言不包含任何可能干扰缓存的编译特性。由于有一些常见的编译模式实际上可能会干扰缓存,因此方言维护者需要仔细检查和测试,并调整任何不适用于缓存的旧模式。
    另请参阅
    第三方方言的缓存 - 第三方方言参与 SQL 语句缓存的背景和示例。
  • 自定义 SQL 类,包括使用 自定义 SQL 构造和编译扩展 创建的所有 DQL / DML 构造,以及对象的临时子类,例如 ColumnTable。对于不包含影响 SQL 编译的子类特定状态信息的简单子类,可以将 HasCacheKey.inherit_cache 属性设置为 True
    另请参阅
    为自定义结构启用缓存支持 - 应用HasCacheKey.inherit_cache属性的指南。

另请参阅

SQL 编译缓存 - 缓存系统概述

对象不会生成缓存密钥,性能影响 - 当为特定构造和/或方言禁用缓存时发出警告的背景信息。


SqlAlchemy 2.0 中文文档(五十四)(3)https://developer.aliyun.com/article/1563181

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
5月前
|
SQL 关系型数据库 API
SqlAlchemy 2.0 中文文档(五十四)(5)
SqlAlchemy 2.0 中文文档(五十四)
51 1
|
5月前
|
SQL 缓存 关系型数据库
SqlAlchemy 2.0 中文文档(五十四)(3)
SqlAlchemy 2.0 中文文档(五十四)
41 1
|
5月前
|
SQL 关系型数据库 测试技术
SqlAlchemy 2.0 中文文档(五十四)(4)
SqlAlchemy 2.0 中文文档(五十四)
48 1
|
5月前
|
Oracle 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(五十一)(1)
SqlAlchemy 2.0 中文文档(五十一)
71 1
|
5月前
|
Oracle 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(五十一)(3)
SqlAlchemy 2.0 中文文档(五十一)
51 1
|
5月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(五十一)(2)
SqlAlchemy 2.0 中文文档(五十一)
45 1
|
5月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(五十一)(4)
SqlAlchemy 2.0 中文文档(五十一)
53 1
|
5月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(五十一)(5)
SqlAlchemy 2.0 中文文档(五十一)
78 1
|
5月前
|
SQL 存储 数据库
SqlAlchemy 2.0 中文文档(五十四)(1)
SqlAlchemy 2.0 中文文档(五十四)
27 0
|
5月前
|
SQL Python
SqlAlchemy 2.0 中文文档(五十七)(5)
SqlAlchemy 2.0 中文文档(五十七)
26 0