Ответ
Мой подход к оптимизации запроса состоит из нескольких шагов:
- Анализ с помощью
EXPLAIN(илиEXPLAIN ANALYZEв PostgreSQL). Смотрю на тип доступа к таблицам (seq scan vs index scan), оцениваю стоимость и количество обрабатываемых строк. - Оптимизация индексов. Ищу поля в условиях
WHERE,JOINиORDER BY, которые не используют индекс. Создаю составные покрывающие индексы, чтобы запрос получал все данные прямо из индекса. - Рефакторинг запроса. Убираю
SELECT *, указываю только нужные столбцы. Упрощаю сложные подзапросы илиJOIN, если это возможно. Проверяю на наличие "горячих" подзапросов, которые выполняются много раз.
Конкретный пример из опыта:
Был запрос для получения последних заказов активных пользователей. EXPLAIN показал полное сканирование таблицы users.
-- Исходный проблемный запрос
SELECT * FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
ORDER BY o.created_at DESC
LIMIT 100;
-- Оптимизированная версия
-- 1. Явный выбор полей
SELECT u.id, u.email, o.id, o.total_amount, o.created_at
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
ORDER BY o.created_at DESC
LIMIT 100;
-- 2. Добавлены индексы
CREATE INDEX idx_users_status ON users(status); -- Для фильтрации
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC); -- Для JOIN и сортировки
После добавления индексов время выполнения запроса сократилось с ~2 секунд до ~50 миллисекунд.
Ответ 18+ 🔞
А, ну ты про оптимизацию SQL-запросов спрашиваешь? Ёпта, тема благодатная, как грязь под ногтями после ремонта.
Слушай, я тебе так скажу: мой подход — это как хороший детектив, который сначала всё обнюхает, а потом уже бьёт. Первым делом я всегда лезу смотреть, что там EXPLAIN показывает. Это как рентген для запроса, понимаешь? Смотрю, как он к таблицам цепляется — сканирует всё подряд, как дурак, или по индексам шурует. Оцениваю, сколько строк перелопатить придётся и во что это по деньгам (стоимости) выльется.
Дальше — святое. Оптимизация индексов. Я ищу, на каких полях в WHERE, JOIN или ORDER BY нету индекса, и начинаю их накручивать. Главная фишка — делать составные покрывающие индексы, чтобы запросу вообще не надо было в саму таблицу лезть, всё из индекса выгребать. Эффективность — овердохуища.
Ну и сам запрос рефакторю. SELECT * — это первое, что летит нахуй. Зачем тащить всё, если нужны три колонки? Потом смотрю на подзапросы — нет ли там таких, которые на каждый чих выполняются. Упрощаю JOIN-ы, если можно.
Вот тебе живой пример, от которого я сам от себя охуел:
Был запрос, который тащил последние заказы активных юзеров. EXPLAIN показал, что он таблицу users целиком, как дурака, сканирует. Представляешь? Полный пиздец.
-- Вот эта хуйня, которая тормозила
SELECT * FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
ORDER BY o.created_at DESC
LIMIT 100;
-- А вот как я её починил
-- 1. Убрал звёздочку, сказал чётко, что надо
SELECT u.id, u.email, o.id, o.total_amount, o.created_at
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
ORDER BY o.created_at DESC
LIMIT 100;
-- 2. Навесил индексы, куда без них
CREATE INDEX idx_users_status ON users(status); -- Чтоб быстро активных найти
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC); -- Чтоб и связать, и отсортировать за раз
И знаешь, что самое приятное? После этих нехитрых манипуляций запрос, который раньше 2 секунды копался, стал отстреливаться за 50 миллисекунд. Вот тебе и вся магия. Никакого шаманства, просто надо головой думать, а не надеяться, что СУБД сама всё порешает.