Короткий ответ
Основные причины — чтение ненужных столбцов и строк, отсутствие или неиспользование индексов на ключах соединения и фильтрации, а также джойны до фильтрации; базовые шаги — выбирать только нужные столбцы, фильтровать как можно раньше, проверять индексы на столбцах JOIN/WHERE и смотреть план выполнения через EXPLAIN.
Как это работает подробнее
Как это работает: SELECT * заставляет СУБД читать и передавать все столбцы, включая возможно крупные текстовые/JSON поля, которые не нужны для анализа — это увеличивает объём I/O и сетевого трафика. Если JOIN выполняется на столбце без индекса, СУБД может быть вынуждена делать полное сканирование одной из таблиц для каждой строки другой (вложенный цикл), что на больших объёмах крайне медленно.
Пример кода
PostgreSQL: план оптимизированного запроса
EXPLAIN ANALYZE
SELECT o.order_id, c.region
FROM orders o
JOIN customers c ON c.customer_id = o.customer_id
WHERE o.order_date >= '2024-01-01';Что использовать на практике
- На практике: полезная последовательность диагностики — (1) посмотреть
EXPLAIN ANALYZEи найти самый дорогой шаг по времени/числу строк; (2) проверить, есть ли индекс на столбцахJOIN/WHERE; (3) перенести фильтры как можно раньше (в подзапрос/CTE до JOIN), чтобы уменьшить объём данных, участвующих в соединении; (4) убрать ненужные столбцы изSELECT. - Проверка: Проверка: сравнить время выполнения (
Execution Timeв выводеEXPLAIN ANALYZE) до и после добавления индекса наorders.customer_idиorders.order_date.
Подводные камни
- Частые ошибки: добавляют индексы «на всё подряд» без анализа реальных запросов — это ускоряет чтение, но замедляет запись и расходует место; оптимизируют один медленный запрос, не проверив, что изменения не ухудшили другие частые запросы к той же таблице.