Ваш SQL швидкий, але API повільний
Ваші запити до бази даних швидкі. Кешування працює. Фонові завдання виконуються належним чином.
Проте ваш API все одно повільний. Навантаження на CPU високе.
Проблема не в базі даних. Проблема в рівні Ruby.
Вузьке місце часто виникає після того, як дані залишають базу даних і потрапляють у ваш застосунок. Це стається через три основні проблеми:
- Надмірна серіалізація
- Надмірне виділення об'єктів
- Повторні обчислення
Ось як їх виправити.
- Припиніть надмірну серіалізацію
Багато розробників перетворюють цілі моделі на JSON.
render json: @shipments
Якщо відправлення має 40 колонок, а вашому фронтенду потрібні лише 5, ви марнуєте цикли CPU. Ви також ризикуєте витоком конфіденційних даних, таких як API-ключі або вартість.
Рішення: повертайте лише ті поля, які вам потрібні.
render json: @shipments.as_json(only: [:id, :tracking_no, :status])
Для ще більшої швидкості використовуйте pluck, щоб отримувати дані у вигляді масивів. Це дозволяє повністю уникнути створення важких об'єктів ActiveRecord.
- Зменште виділення об'єктів
Кожен об'єкт, який створює Ruby, споживає пам'ять. Створення тисяч об'єктів під час одного запиту змушує Garbage Collector (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. - Високе виділення: Створюйте менше об'єктів у циклах.
- Повторні обчислення: Використовуйте мемоїзацію для повторного використання результатів.
Оптимізація бази даних означає запит меншої кількості даних. Оптимізація застосунку означає виконання меншої кількості зайвої роботи, коли дані вже отримано.
Джерело: https://dev.to/danewu/your-sql-is-fast-but-the-api-is-slow-its-the-ruby-layer-2fno
