Маю запит:
SELECT u.name, o.total, p.title
FROM users u
JOIN orders o ON o.user_id = u.id
JOIN products p ON p.id = o.product_id
WHERE u.country = "UA" AND o.created_at > "2026-01-01"
ORDER BY o.total DESC
LIMIT 100;
Виконується 8 секунд на 5 млн рядків в orders. EXPLAIN показує Using temporary; Using filesort. Як виправити?
Питання закрите для нових відповідей.
Експерт обрав найкращою
1 Відповідь
Класична проблема — БД виконує full scan і сортування у памʼяті. Все вирішується правильними composite indexes.
Крок 1: проаналізуйте план виконання
EXPLAIN ANALYZE
SELECT u.name, o.total, p.title
FROM users u JOIN orders o ON ... ;
Дивіться, де найдорожча операція (Cost). Зазвичай це Seq Scan на orders.
Крок 2: composite index під ваш запит
-- Для users: пошук по country
CREATE INDEX idx_users_country ON users(country);
-- Для orders: ключовий — покриває WHERE + ORDER BY
CREATE INDEX idx_orders_user_created_total
ON orders(user_id, created_at DESC, total DESC);
Порядок колонок важливий: ставте першими ті, що у JOIN, потім у WHERE, останнім — для ORDER BY.
Крок 3: додайте covering index (якщо потрібно)
Якщо БД все одно йде на таблицю — додайте всі вибрані поля у індекс (PostgreSQL — INCLUDE):
CREATE INDEX idx_orders_covering
ON orders(user_id, created_at DESC)
INCLUDE (total, product_id);
Крок 4: перевірте денормалізацію
Якщо запит виконується часто і дані змінюються рідко — використайте materialized view або кешування результату в Redis.
Очікуваний результат
З правильними індексами час виконання падає з 8 с до 50-200 мс. Якщо ні — проблема в самих JOIN-ах (наприклад, NULL у user_id).
Експерт обрав найкращою