Як неіндексована колонка вбила нашу базу даних

Один відсутній індекс перетворив API зі швидкістю 8 мс на 8-секундний кошмар.

Перед великим релізом ми провели навантажувальне тестування. Локальна розробка легко справлялася зі 100 рядками. На стейджингу ми симулювали 500 користувачів на 1,5 мільйонах рядків.

Усе зламалося.

  • Час відповіді API зріс з 45 мс до 8 000 мс.
  • Завантаження CPU бази даних сягнуло 100 %.
  • Пули з'єднань вичерпалися.
  • Запити завершувалися за тайм-аутом.

Винуватцем був простий запит, який отримував історію замовлень за user_id та status.

Запуск EXPLAIN ANALYZE у PostgreSQL показав Sequential Scan. Через відсутність індексу на user_id рушій зчитував усі 1,5 мільйона рядків для кожного запиту.

При 100 одночасних запитах база даних сканувала 150 мільйонів рядків за раз.

Виправлення зайняло п'ять хвилин. Ми створили складений індекс на (user_id, status, created_at DESC) за допомогою CREATE INDEX CONCURRENTLY, щоб таблиця залишалася доступною.

Результати:

  • Час виконання запиту впав з 8 150 мс до 0,14 мс.
  • Затримка API зменшилася з 8 секунд до 12 мс.
  • Використання CPU впало зі 100 % до менш ніж 8 %.

Вивчені уроки:

  • Локальні тести можуть вводити в оману; 100 рядків — це не заміна мільйона.
  • Індексуйте зовнішні ключі — більшість ORM цього не роблять.
  • Запускайте EXPLAIN ANALYZE; база даних сама вкаже на проблему.
  • Оптимізуйте запити перед тим, як купувати нове обладнання.

Не масштабуйте спочатку сервери. Масштабуйте запити.

Джерело: https://dev.to/mia_keller_ffd2584c046ecb/how-an-unindexed-column-silently-killed-our-database-under-load-and-the-5-minute-fix-m32