我将 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 函数以及一些属性加载策略将利用主缓存之外的各个映射器缓存。
..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 层,并且不确定如何在我的案例中应用它。
有什么想法可能导致这种延迟吗?
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 造成如此大的延迟,但现在......希望这对其他人也有帮助。