Я использую ORM SQLAlchemy. У меня есть модель, которая имеет множественные отношения "многие ко многим":
User
User <--MxN--> Organization
User <--MxN--> School
User <--MxN--> Credentials
Я использую эти таблицы , поэтому есть также таблицы User_to_Organization, User_to_School и User_to_Credentials, которые я непосредственно не использую.
Теперь, когда я пытаюсь загрузить одного пользователя (используя его идентификатор PK) и его отношения (и связанные с ним модели), используя объединенную загрузку, я получаю ужасную производительность (15 + секунд). Я предполагаю, что это связано с этой проблемой:
При использовании нескольких уровней глубины с объединенной загрузкой или подзапросами загрузка коллекций внутри коллекций будет умножать общее количество строк, выбранных декартово. Обе формы активной загрузки всегда соединяются с исходным родительским классом.
Если я введу другой уровень или два в иерархию:
Organization <--1xN--> Project
School <--1xN--> Course
Project <--MxN--> Credentials
Course <--MxN--> Credentials
Завершение запроса занимает 50 секунд, хотя общий объем записей в каждой таблице довольно мал.
Используя ленивую загрузку, мне необходимо вручную загрузить каждую взаимосвязь, и на сервер многократные поездки.
например. Операции, выполняемые последовательно как запросы:
- Получить пользователя
- Получить пользовательские организации
- Получить пользовательские школы
- Получить учетные данные пользователя
- Для каждой организации получите свои проекты
- Для каждой школы получите свои курсы
- Для каждого проекта получите свои учетные данные
- Для каждого курса получите свои учетные данные
Тем не менее, все это заканчивается менее чем за 200 мс.
Мне было интересно, есть ли вообще возможность использовать ленивую загрузку, но выполняйте параллельные запросы загрузки. Например, используя модуль concurrent
, asyncio
или используя gevent
.
например. Шаг 1 (параллельно):
- Получить пользователя
- Получить пользовательские организации
- Получить пользовательские школы
- Получить учетные данные пользователя
Шаг 2 (параллельно):
- Для каждой организации получите свои проекты
- Для каждой школы получите свои курсы
Шаг 3 (параллельно):
- Для каждого проекта получите свои учетные данные
- Для каждого курса получите свои учетные данные
На самом деле, на данный момент может также работать загрузка типа подзапроса, то есть возвращать Organization и OrganizationID/Project/Credentials в два отдельных запроса:
например. Шаг 1 (параллельно):
- Получить пользователя
- Получить пользовательские организации
- Получить пользовательские школы
- Получить учетные данные пользователя
Шаг 2 (параллельно):
- Получить организации
- Получить школы
- Получить проекты организаций, присоединиться к учетным данным
- Получите курсы школ, присоединитесь к Credentials