Кейс: как я снял нагрузку с сервера и базы, просто добавив индексы в PostgreSQL

Есть баги, которые честно говорят, что они баги: “500 Internal Server Error”, “syntax error at or near”. А есть баги-лицемеры.

Открываю бэкофис, жму привычную кнопку — и в ответ:

Request Error (Error: Network Error)

Ну конечно. Сеть. Хотя интернет работает, Wi-Fi не мигает, кот не перегрыз кабель. Значит, это не сеть. Это — классика жанра: запрос в базе уехал в отпуск и не вернулся вовремя.

Шаг 1. Воспроизведение (или “поймай меня, если сможешь”)

Я делаю то же самое, что делал пользователь: тот же экран, тот же фильтр/кнопка. Ошибка повторяется.

Отлично: баг не стеснительный, ловится руками.

Шаг 2. Логи

Дальше по чеклисту:

  • лезу в backend-логи,
  • нахожу endpoint,
  • вытаскиваю реальный SQL (с параметрами),
  • иду в базу и гоняю его на сервере, а не “у меня в консольке на деве”.

Делаю замер:

EXPLAIN (ANALYZE, BUFFERS)-- тот самый запрос;

Потому что “кажется, медленно” — это эмоция. А EXPLAIN ANALYZE — это диагноз.

Шаг 3. План выполнения: где съедаются секунды

На плане видно главное: запрос не “просто выбирает 50 строк”. Он:

  • фильтрует по условиям,
  • выполняет подзапросы/SubPlan,
  • дергает функции,
  • и в какой-то момент вынужден читать лишнее (а потом выкидывать).
Как “было больно” — 27 секунд
Как “было больно” — 27 секунд
Как “стало легче” — 12 секунд
Как “стало легче” — 12 секунд

Шаг 4. Я не переписывал запрос. Я дал базе “указатель”

Дальше я сделал то, что в PostgreSQL почти всегда дает самый быстрый эффект:

  1. посмотрел, где именно уходит время (самые дорогие узлы плана);
  2. проверил, по каким колонкам фильтруем/джойним/сортируем;
  3. посмотрел структуры таблиц, в которые упираются функции/подпланы;
  4. добавил точечные индексы под реальные условия.

Важно: я не “накидал индексов на всё подряд”. Я добавил их ровно туда, где план показывал боль.

Финал. Минус таймауты, плюс спокойствие

После индексов:

  • запрос стал отвечать заметно быстрее (с ~27с до ~12с, потом до ~4с),
  • сервер перестал в пике страдать от лишнего чтения,
  • а на фронте “Network Error” внезапно исцелился, потому что запрос перестал выбивать таймаут.

И да, это тот редкий случай, когда “добавил индексы” — не отмазка, а реально решение.

Что такое индекс

Представь бумажную книгу на 1000 страниц. И тебе нужно найти слово “PostgreSQL”.

Без алфавитного указателя (без индекса)

Ты делаешь “Seq Scan по книге”:

  • открываешь страницу 1,
  • читаешь,
  • не нашёл — страница 2,
  • страница 837 — нашёл.

Это линейный способ: чем больше книга, тем больнее.

С алфавитным указателем (с индексом)

Ты открываешь конец книги: “Указатель”. Там по алфавиту:

  • PostgreSQL → 837, 842, 901

И ты сразу идёшь на нужные страницы.

1
1
1 комментарий