Ваш SQL работает быстро, но API — медленный

Ваши запросы к базе данных работают быстро. Кэширование работает. Фоновые задачи выполняются нормально.

Тем не менее, ваш API всё еще медленный. Нагрузка на CPU высокая.

Проблема не в базе данных. Проблема в слое Ruby.

Узкое место часто возникает после того, как данные покидают базу данных и попадают в ваше приложение. Это происходит из-за трех основных проблем:

  • Избыточная сериализация
  • Чрезмерное выделение объектов
  • Повторяющиеся вычисления

Вот как их исправить.

  1. Прекратите избыточную сериализацию

Многие разработчики преобразуют целые модели в JSON.

render json: @shipments

Если у отгрузки (shipment) 40 колонок, а фронтенду нужны только 5, вы тратите циклы CPU впустую. Вы также рискуете раскрыть конфиденциальные данные, такие как API-ключи или стоимость.

Решение: возвращайте только нужные поля.

render json: @shipments.as_json(only: [:id, :tracking_no, :status])

Для еще большей скорости используйте pluck, чтобы получать данные в виде массивов. Это позволит полностью избежать создания тяжелых объектов ActiveRecord.

  1. Сократите выделение объектов

Каждый объект, который создает Ruby, потребляет память. Создание тысяч объектов в рамках одного запроса заставляет сборщик мусора (GC) работать интенсивнее. Это замедляет всю систему.

Избегайте создания новых хешей или строк внутри циклов.

Плохо:

@shipments.map do |s|
  { label: "#{s.tracking_no} - #{s.status.upcase}" }
end

Хорошо: Выносите статические данные за пределы цикла. Выполняйте больше работы на стороне базы данных, а не в Ruby.

  1. Избегайте повторяющихся вычислений

Если вы вызываете один и тот же метод несколько раз в рамках одного запроса, вы тратите время впустую.

Пример:

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