🔥 Индексы в PostgreSQL: почему твой продакшн тормозит как Windows Vista
Знаешь, что общего между твоей базой данных и трехлетним ребенком? Оба умеют орать посреди ночи, и в обоих случаях это твоя вина. Только ребенка ты кормил и менял памперсы, а в базу индексы не завез. Поздравляю, теперь твой SELECT работает 8 секунд вместо 3 миллисекунд.
🐕 Почему даже собака умнее твоего тимлида
Представь: у тебя книга на 500 страниц, и тебе нужно найти слово "ебанутый". Что сделает нормальный человек? Откроет предметный указатель сзади. Что сделает твоя база без индексов? Прочитает ВСЕ 500 СТРАНИЦ от начала до конца.
Моя собака понимает, что миска с едой стоит в углу кухни – он не обыскивает всю квартиру каждый раз. А твой PostgreSQL при запросе WHERE email = 'ivan@corp.com' сканирует 5 миллионов строк. Каждый. Ебаный. Раз.
Стоимость твоей тупости:
Seq Scan по 5M строк: ~800ms
Index Scan: ~3ms
Разница: в 250 раз медленнее
Пользователи ушли: пока ты читаешь этот текст
💩 Отмазка | Реальность
"У нас всего 100К записей, индексы не нужны"
Реальность: Даже на 10K строк разница между 50ms и 2ms имеет значение, когда запрос выполняется 1000 раз в минуту. Это 48 секунд CPU времени VS 2 секунды. За месяц ты платишь на $300 больше за инстанс, потому что "всего 100K записей".
"Мы добавили индекс, но ничего не изменилось"
Реальность: Ты добавил индекс на колонку created_at, но запрос использует WHERE DATE(created_at) = '2025-01-15'. Функция DATE() делает индекс бесполезным, ебать тебя в космос. PostgreSQL не может использовать индекс, если ты трансформируешь колонку.
🔍 Как узнать, что ты накосячил
Открой консоль и запусти:
```
sql
Или проверь индексы, которые НИКТО НЕ ИСПОЛЬЗУЕТ:
sql
🏆 Реальный кейс от Петрова П.П.
Компания "ХуевыРешения Inc" делала выборку пользователей по статусу:
```sql
Проблемы:
Нет индекса на status
Нет индекса на created_at
PostgreSQL сканирует 8M строк
После того как выебали всех:
```
sql
Стоимость косяка: $400/месяц на оверпрайснутый RDS инстанс. Потому что Петров П.П. не знает что такое индексы.
✅ Что делать прямо сейчас
Проверь эти запросы:
SELECT с WHERE на колонках без индексов
JOIN на колонках без индексов (особенно foreign keys)
ORDER BY на колонках без индексов
Добавь индексы:
```
sql
🐕 Заключение: собака vs твой сеньор
Моя собака запоминает где лежит его игрушка после одного раза. Твой сеньор разработчик третий год пишет запросы без индексов. Собака приносит мяч за 5 секунд. Твой запрос работает 5 секунд на табличке в 100K строк.
Вопрос: кого из них стоит повысить?
Итого:
Индексы = предметный указатель в книге
Без индексов = читать всю книгу каждый раз
Собаки умнее некоторых разработчиков
Твой продакшн тормозит потому что ты ленивый
P.S. В следующей статье разберем VACUUM и почему твоя база в 3 часа ночи легла. Спойлер: ты, блять, забыл про autovacuum.
Знаешь, что общего между твоей базой данных и трехлетним ребенком? Оба умеют орать посреди ночи, и в обоих случаях это твоя вина. Только ребенка ты кормил и менял памперсы, а в базу индексы не завез. Поздравляю, теперь твой SELECT работает 8 секунд вместо 3 миллисекунд.
🐕 Почему даже собака умнее твоего тимлида
Представь: у тебя книга на 500 страниц, и тебе нужно найти слово "ебанутый". Что сделает нормальный человек? Откроет предметный указатель сзади. Что сделает твоя база без индексов? Прочитает ВСЕ 500 СТРАНИЦ от начала до конца.
Моя собака понимает, что миска с едой стоит в углу кухни – он не обыскивает всю квартиру каждый раз. А твой PostgreSQL при запросе WHERE email = 'ivan@corp.com' сканирует 5 миллионов строк. Каждый. Ебаный. Раз.
Стоимость твоей тупости:
Seq Scan по 5M строк: ~800ms
Index Scan: ~3ms
Разница: в 250 раз медленнее
Пользователи ушли: пока ты читаешь этот текст
💩 Отмазка | Реальность
"У нас всего 100К записей, индексы не нужны"
Реальность: Даже на 10K строк разница между 50ms и 2ms имеет значение, когда запрос выполняется 1000 раз в минуту. Это 48 секунд CPU времени VS 2 секунды. За месяц ты платишь на $300 больше за инстанс, потому что "всего 100K записей".
"Мы добавили индекс, но ничего не изменилось"
Реальность: Ты добавил индекс на колонку created_at, но запрос использует WHERE DATE(created_at) = '2025-01-15'. Функция DATE() делает индекс бесполезным, ебать тебя в космос. PostgreSQL не может использовать индекс, если ты трансформируешь колонку.
🔍 Как узнать, что ты накосячил
Открой консоль и запусти:
```
sql
-- Проверяем запрос
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'test@mail.ru';
-- Видишь "Seq Scan on users"? ПОЗДРАВЛЯЮ, ТЫ ПРОСРАЛ
-- cost=0.00..145000.00 - это пиздец, друг
-- Должно быть: Index Scan, cost около 0.43..8.45Или проверь индексы, которые НИКТО НЕ ИСПОЛЬЗУЕТ:
sql
SELECT
schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
AND indexname NOT LIKE 'pg_toast%';
-- idx_scan = 0 значит индекс жрет место и никому не нужен
-- Как твой проджект-менеджер
```🏆 Реальный кейс от Петрова П.П.
Компания "ХуевыРешения Inc" делала выборку пользователей по статусу:
```sql
-- Код долбоеба:
SELECT * FROM orders
WHERE status IN ('pending', 'processing')
ORDER BY created_at DESC
LIMIT 50;
-- Execution time: 4500ms
-- БЛЯТЬ, КТО ЭТО НАПИСАЛ?!
```Проблемы:
Нет индекса на status
Нет индекса на created_at
PostgreSQL сканирует 8M строк
После того как выебали всех:
```
sql
-- Создаем составной индекс (порядок ВАЖЕН!)
CREATE INDEX idx_orders_status_created
ON orders(status, created_at DESC)
WHERE status IN ('pending', 'processing');
-- Execution time: 12ms
-- Экономия: 4488ms на запрос
-- Запросов в день: ~50K
-- Сэкономили: 62 часа CPU времени в день
```Стоимость косяка: $400/месяц на оверпрайснутый RDS инстанс. Потому что Петров П.П. не знает что такое индексы.
✅ Что делать прямо сейчас
Проверь эти запросы:
SELECT с WHERE на колонках без индексов
JOIN на колонках без индексов (особенно foreign keys)
ORDER BY на колонках без индексов
Добавь индексы:
```
sql
-- На foreign keys (да, PostgreSQL их НЕ индексирует автоматически)
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- На поля для поиска
CREATE INDEX idx_users_email ON users(email);
-- Partial индексы для частых условий
CREATE INDEX idx_active_users ON users(id)
WHERE is_active = true;
```🐕 Заключение: собака vs твой сеньор
Моя собака запоминает где лежит его игрушка после одного раза. Твой сеньор разработчик третий год пишет запросы без индексов. Собака приносит мяч за 5 секунд. Твой запрос работает 5 секунд на табличке в 100K строк.
Вопрос: кого из них стоит повысить?
Итого:
Индексы = предметный указатель в книге
Без индексов = читать всю книгу каждый раз
Собаки умнее некоторых разработчиков
Твой продакшн тормозит потому что ты ленивый
P.S. В следующей статье разберем VACUUM и почему твоя база в 3 часа ночи легла. Спойлер: ты, блять, забыл про autovacuum.