Ответ
Ответ не найден
Ответ 18+ 🔞
А, ну ты посмотри, какая тема подъехала! Вот сидишь такой, пьешь кофеек, а тут тебе — бац! — про оптимизацию запросов в PostgreSQL. Ну что ж, давай разберем эту пиздопроебибну, но по-человечьи.
Слушай сюда, история классическая. Представь: у тебя таблица, ну, orders, там миллионы записей. И ты такой пишешь запрос, чтобы найти заказы за вчера для конкретного юзера.
SELECT * FROM orders
WHERE user_id = 12345
AND created_at >= '2023-10-25'
AND created_at < '2023-10-26';
Казалось бы, что тут такого? Ан нет! База смотрит на это и думает: «Э, сабака сука, ну и хуйня». Потому что если индексов нет, ей придется полную таблицу сканировать, это пиздец как долго. Она каждую строчку будет смотреть: «Юзер 12345? Нет. Юзер 12345? Нет». Овердохуища работы.
Вот тут и начинается магия. Ты смотришь EXPLAIN ANALYZE на этот запрос, а там Seq Scan on orders. Это как если бы ты искал иголку в стоге сена, перебирая каждую травинку по отдельности. Волнение ебать начинается, когда стог — на всю страну.
Так, а что делает умный человек? Правильно, индексы ставит. Но не абы какие! Если ты сделаешь два отдельных индекса на user_id и на created_at, планировщик, тот ещё хитрая жопа, может выбрать только один из них. И будет не сильно быстрее.
Секрет в том, чтобы сделать комбинированный индекс:
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at);
Теперь запрос — просто песня! База сразу прыгает в нужную часть индекса по user_id и там уже быстро фильтрует по дате. EXPLAIN покажет Index Scan или даже Index Only Scan — красота! Это уже не поиск иголки, а открытие нужной коробочки в отсортированном комоде.
Но и это ещё не всё, полупидор! Допустим, у тебя запрос такой:
SELECT * FROM orders
WHERE user_id = 12345
AND status = 'processed'
AND created_at >= '2023-10-25';
С индексом (user_id, created_at) поле status не покрыто. База найдет все заказы юзера за дату, но потом будет вручную проверять каждый на статус. Удивление пиздец, но так бывает.
Тут два пути:
- Расширить индекс:
(user_id, status, created_at). Тогда всё будет идеально для ЭТОГО запроса. - Использовать
INCLUDEв индексе (если PostgreSQL 11+):(user_id, created_at) INCLUDE (status). Данные по статусу будут в самом индексе, не нужно ходить в таблицу.
Главное помнить: индексы — они как девушки. Если их мало — плохо, если слишком много — тоже хуй с горы. Каждый индекс замедляет вставку и обновление, потому что его тоже надо поддерживать. Накопишь их манда с ушами — и пишешь быстро, а обновляешь со скоростью черепахи в сиропе.
Короче, мораль простая: всегда смотри EXPLAIN ANALYZE, не верь планировщику на слово (доверия ебать ноль), и создавай индексы с умом, под конкретные тяжелые запросы. А то будет тебе хиросима и нигерсраки в продакшене в пятницу вечером.