Sqlalchemy 第一次查询时很慢

问题描述 投票:0回答:2

我将 Sqlalchemy(2.0.3) 与 python3.10 一起使用,在全新容器启动后,执行特定查询需要大约 2.2 秒,同一查询的所有连续调用需要大约 70 毫秒才能执行。我正在使用 PostgreSQL,在 DataGrip 中执行原始查询需要 40-70 毫秒。 这是代码:

self._Session = async_sessionmaker(self._engine, expire_on_commit=False)

...

@property
def session(self):
   return self._Session

...

async with PostgreSQL().session.begin() as session:
    total_functions = aliased(db_models.Function)
    finished_functions = aliased(db_models.Function)
    failed_functions = aliased(db_models.Function)
    stmt = (
        select(
            db_models.Job,
            func.count(distinct(total_functions.id)).label("total"),
            func.count(distinct(finished_functions.id)).label("finished"),
            func.count(distinct(failed_functions.id)).label("failed")
        )
        .where(db_models.Job.project_id == project_id)
        .outerjoin(db_models.Job.packages)
        .outerjoin(db_models.Package.modules)
        .outerjoin(db_models.Module.functions.of_type(total_functions))
        .outerjoin(finished_functions, and_(
               finished_functions.module_id == db_models.Module.id,
               finished_functions.progress == db_models.FunctionProgress.FINISHED
            ))
        .outerjoin(failed_functions, and_(
            failed_functions.module_id == db_models.Module.id,
            or_(
                failed_functions.state == db_models.FunctionState.FAILED,
                failed_functions.state == db_models.FunctionState.TERMINATED,
            ))
           )
        .group_by(db_models.Job.id)
    )
    start = time.time()
    yappi.set_clock_type("WALL")
    with yappi.run():
        job_infos = await session.execute(stmt)
    yappi.get_func_stats().print_all()
    end = time.time()

我尝试过并发现的事情:

  • 问题与连接或查询数据库数据库无关。在服务启动时,我建立连接并进行一些其他查询。
  • 问题很可能与缓存无关。我已经使用
    query_cache_size=0
    禁用了缓存,但是我不能 100% 确定它有效,因为文档说:

与工作单元持久性相关的 ORM 函数以及一些属性加载策略将利用主缓存之外的各个映射器缓存。

  • Profiler 没有显示任何引起我注意的内容:
..urrency_py3k.py:130 greenlet_spawn  2/1    0.000000  2.324807  1.162403  
..rm/session.py:2168 Session.execute  1      0.000028  2.324757  2.324757  
..0 _UnixSelectorEventLoop._run_once  11     0.000171  2.318555  0.210778  
..syncpg_cursor._prepare_and_execute  1      0.000054  2.318187  2.318187  
..cAdapt_asyncpg_connection._prepare  1      0.000020  2.316333  2.316333  
..nnection.py:533 Connection.prepare  1      0.000003  2.316154  2.316154  
..nection.py:573 Connection._prepare  1      0.000017  2.316151  2.316151  
..n.py:359 Connection._get_statement  2/1    0.001033  2.316122  1.158061  
..ectors.py:452 EpollSelector.select  11     0.000094  2.315352  0.210487  
..y:457 Connection._introspect_types  1      0.000025  2.314904  2.314904  
..ction.py:1669 Connection.__execute  1      0.000027  2.314879  2.314879  
..ion.py:1699 Connection._do_execute  1      2.314095  2.314849  2.314849  
...py:2011 Session._execute_internal  1      0.000034  0.006174  0.006174

我还看到有人可能会禁用每个连接的缓存:

with engine.connect().execution_options(compiled_cache=None) as conn:
    conn.execute(table.select())

但是我正在使用 ORM 层,并且不确定如何在我的案例中应用它。

有什么想法可能导致这种延迟吗?

python sql postgresql sqlalchemy
2个回答
6
投票

经过几个小时的谷歌搜索,我找到了这篇帖子。简而言之,问题与缺乏 Postgres 使用的 JIT 所需的依赖项(在某些 alpine docker 镜像中)有关。有关详细信息,我强烈建议您阅读帖子和作者提供的现实生活影响。 Sqlalchemy 的实际解决方案是关闭 JIT:

engine = create_async_engine( "postgresql+asyncpg://user:password@localhost/tmp", connect_args={"server_settings": {"jit": "off"}}, )
参考

文档


0
投票

tldr:MacOS 上 Docker 上的 PostgreSQL 引入了连接创建延迟;使用本地安装的 PostgreSQL 版本进行开发


我在第一个请求时遇到了整整

30 秒的延迟

经过几天的故障排除 - 配置 JIT、更改池大小、通过引擎手动创建连接、创建更多会话/重用会话、查看

sessionmaker

 的所有参数并进行尝试、在 12/13/12 之间更改 PostgreSQL 版本2016 年 14 月 15 日,阅读 Uvicorn + SQL Alchemy + FastAPI 的最新变更日志,将驱动程序从 psycopg2 更改为 pg8000 等其他驱动程序,升级软件包并打开和关闭中间件,使用 
SELECT 1
 -
等简单查询进行测试

我决定全程断点,看看哪里有问题。

sqlalchemy/lib/sqlalchemy/pool/base.py:712


@classmethod def checkout(cls, pool: Pool) -> _ConnectionFairy: if TYPE_CHECKING: rec = cast(_ConnectionRecord, pool._do_get()) else: rec = pool._do_get() try: dbapi_connection = rec.get_connection() except BaseException as err: ...
我在 

rec = pool._do_get()

 上延迟了整整 30 秒。将问题隔离到创建与数据库的连接时,我记得 
pgadmin
 和我的 IDE 都不是连接到数据库最快的,并且存在明显的延迟(到目前为止我忽略了)。

我的数据库在 Mac OS 上的 Docker 上以简单的

docker-compose.yaml

 文件运行。我将其更改为指向本地运行的 PostgreSQL 数据库,结果发现:连接时间非常快。

我仍然不确定它是否是 Mac OS 版本的 Docker、Docker 本身、我特定机器上的 PostgreSQL 映像等等。但我很高兴能修复它。

也许有一天我会知道为什么 Docker 造成如此大的延迟,但现在......希望这对其他人也有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.