如何在加载关系时指示SQLAlchemy ORM并行执行多个查询?

adv*_*512 10 python mysql parallel-processing orm sqlalchemy

我正在使用SQLAlchemy的ORM.我有一个具有多个多对多关系的模型:

User
User <--MxN--> Organization
User <--MxN--> School
User <--MxN--> Credentials
Run Code Online (Sandbox Code Playgroud)

我正在使用关联表来实现这些,因此还有我不直接使用的User_to_Organization,User_to_School和User_to_Credentials表.

现在,当我尝试使用加入的热切加载加载单个用户(使用其PK标识符)及其关系(和相关模型)时,我会得到可怕的性能(15秒以上).我认为这是由于这个问题:

当多个深度级别与连接或子查询加载一起使用时,在集合内加载集合将乘以以笛卡尔方式提取的总行数.两种形式的急切加载始终从原始父类加入.

如果我在层次结构中引入另一个或两个级别:

Organization <--1xN--> Project
School <--1xN--> Course
Project <--MxN--> Credentials
Course <--MxN--> Credentials
Run Code Online (Sandbox Code Playgroud)

即使每个表中的记录总量相当小,查询也需要50秒以上才能完成.

使用延迟加载,我需要手动加载每个关系,并且有多次到服务器的往返.

例如,作为查询连续执行的操作:

  • 获得用户
  • 获取用户的组织
  • 获取用户的学校
  • 获取用户的凭据
  • 对于每个组织,获取其项目
  • 为每所学校,获得其课程
  • 对于每个项目,获取其凭据
  • 对于每个课程,获取其凭据

不过,这一切都在不到200毫秒内完成.

我想知道是否确实使用延迟加载,但执行并行加载查询的关系.例如,使用concurrent模块,asyncio或使用gevent.

例如步骤1(并行):

  • 获得用户
  • 获取用户的组织
  • 获取用户的学校
  • 获取用户的凭据

第2步(并行):

  • 对于每个组织,获取其项目
  • 为每所学校,获得其课程

第3步(并行):

  • 对于每个项目,获取其凭据
  • 对于每个课程,获取其凭据

实际上,此时,进行子查询类型加载也可以工作,即在两个单独的查询中返回Organization和OrganizationID/Project/Credentials:

例如步骤1(并行):

  • 获得用户
  • 获取用户的组织
  • 获取用户的学校
  • 获取用户的凭据

第2步(并行):

  • 获得组织
  • 获得学校
  • 获取组织的项目,加入凭证
  • 获取学校课程,加入证书

Ric*_*mes 0

MySQL 在单个连接中没有并行性。ORM 要做到这一点需要多个到 MySQL 的连接。一般来说,尝试这样做的开销是“不值得的”。

要获取 a user、 his OrganizationsSchools等,都可以通过单个查询完成(在 mysql 中):

SELECT user, organization, ...
    FROM Users
    JOIN Organizations ON ...
    etc.
Run Code Online (Sandbox Code Playgroud)

这比

SELECT user FROM ...;
SELECT organization ... WHERE user = ...;
etc.
Run Code Online (Sandbox Code Playgroud)

(这不是“并行性”。)

或者也许你的“步骤”不太“正确”?...

SELECT user, organization, project
    FROM Users
    JOIN Organizations ...
    JOIN Projects ...
Run Code Online (Sandbox Code Playgroud)

只需一步即可获取所有用户及其所有组织和项目。

但“用户”是否与“项目”相关联?如果不是,那么这是错误的方法。

如果 ORM 没有提供生成此类查询的机制,那么它就会“妨碍”。