Ваш SQL работает быстро, но API — медленный
Ваши запросы к базе данных работают быстро. Кэширование работает. Фоновые задачи выполняются нормально.
Тем не менее, ваш API всё еще медленный. Нагрузка на CPU высокая.
Проблема не в базе данных. Проблема в слое Ruby.
Узкое место часто возникает после того, как данные покидают базу данных и попадают в ваше приложение. Это происходит из-за трех основных проблем:
- Избыточная сериализация
- Чрезмерное выделение объектов
- Повторяющиеся вычисления
Вот как их исправить.
- Прекратите избыточную сериализацию
Многие разработчики преобразуют целые модели в JSON.
render json: @shipments
Если у отгрузки (shipment) 40 колонок, а фронтенду нужны только 5, вы тратите циклы CPU впустую. Вы также рискуете раскрыть конфиденциальные данные, такие как API-ключи или стоимость.
Решение: возвращайте только нужные поля.
render json: @shipments.as_json(only: [:id, :tracking_no, :status])
Для еще большей скорости используйте pluck, чтобы получать данные в виде массивов. Это позволит полностью избежать создания тяжелых объектов ActiveRecord.
- Сократите выделение объектов
Каждый объект, который создает Ruby, потребляет память. Создание тысяч объектов в рамках одного запроса заставляет сборщик мусора (GC) работать интенсивнее. Это замедляет всю систему.
Избегайте создания новых хешей или строк внутри циклов.
Плохо:
@shipments.map do |s|
{ label: "#{s.tracking_no} - #{s.status.upcase}" }
end
Хорошо: Выносите статические данные за пределы цикла. Выполняйте больше работы на стороне базы данных, а не в Ruby.
- Избегайте повторяющихся вычислений
Если вы вызываете один и тот же метод несколько раз в рамках одного запроса, вы тратите время впустую.
Пример:
def total_weight
shipments.sum(&:weight)
end
Если ваш view, helper и serializer вызывают этот метод, вы вычисляете сумму трижды.
Решение: используйте мемоизацию.
def total_weight
@total_weight ||= shipments.sum(&:weight)
end
Это гарантирует, что вычисления будут выполнены только один раз за запрос.
Сводная таблица:
- Избыточная сериализация: Возвращайте только нужные поля или используйте
pluck. - Высокое выделение: Создавайте меньше объектов в циклах.
- Повторяющиеся вычисления: Используйте мемоизацию для повторного использования результатов.
Оптимизация базы данных означает запрос меньшего объема данных. Оптимизация приложения означает выполнение меньшего объема лишней работы после того, как вы получили данные.
Source: https://dev.to/danewu/your-sql-is-fast-but-the-api-is-slow-its-the-ruby-layer-2fno
