28 lines
2.9 KiB
Markdown
28 lines
2.9 KiB
Markdown
# N+1 запросов в списках (изменение 019)
|
|||
|
|
|
||
|
|
Находка ревью № 9, серьёзность — низкая (производительность).
|
||
|
|
|
||
|
|
## Context
|
||
|
|
Счётчики и связанные данные догружаются отдельными запросами на каждую строку: `_device_out` (2 запроса на устройство — до 1 000 на странице),
|
||
|
|
`_isp_out` (организация), `_vrf_out`, `_type_out`, `_org_out` (счётчики), «Обзор» (`_prefix_outs` для всех активных префиксов с `_depths`/`_capacities` по организациям).
|
||
|
|
|
||
|
|
## Решение
|
||
|
|
1. **Пакетные выходные функции** — принимают список строк и делают фиксированное число запросов:
|
||
|
|
- устройства: один запрос адресов `WHERE device_id IN (…)` + словарь типов (типов мало — один `SELECT` всех);
|
||
|
|
- операторы: `selectinload(Isp.networks)` + словарь организаций по `IN`;
|
||
|
|
- VRF / типы / организации: счётчики одним `GROUP BY` по `IN (…)`;
|
||
|
|
- одиночные эндпоинты (`GET /devices/{id}` и т.п.) вызывают пакетную функцию со списком из одного элемента.
|
||
|
|
2. **Обзор:** считать ёмкость и загрузку одним SQL-запросом по листовым активным IPv4-префиксам (лист — префикс без детей) вместо полной сборки `PrefixOut` по всем префиксам;
|
||
|
|
`top_prefixes` — `_prefix_outs` только для 4 выбранных.
|
||
|
|
3. Формат ответов не меняется.
|
||
|
|
4. Контроль: в тестовом режиме — счётчик запросов через событие `before_cursor_execute` (фикстура), чтобы зафиксировать «не больше K запросов на список».
|
||
|
|
|
||
|
|
## Файлы
|
||
|
|
`app/api/v1/refs.py`, `app/api/v1/overview.py`, `app/api/v1/prefixes.py` (при необходимости), `tests/test_api.py`.
|
||
|
|
|
||
|
|
## Тест
|
||
|
|
Один тест уровня функций (сессия SQLAlchemy к БД стенда, счётчик через `before_cursor_execute`): пакетный вывод 20 устройств — не больше 3 запросов.
|
||
|
|
Внешние API-тесты счётчик не видят, поэтому тест вызывает функции напрямую.
|
||
|
|
|
||
|
|
## Проверка
|
||
|
|
`pytest -q`; сравнение ответов API до/после на демо-данных (скрипт диффа JSON в scratchpad) — идентичны; замер времени `GET /devices?limit=500` на синтетических данных.
|