Индексы SQL: EXPLAIN ANALYZE и оптимизация запросов
Индексы SQL помогают ускорять выборки, но сами по себе не гарантируют быстрый запрос. Разберём EXPLAIN ANALYZE, план запроса SQL и условия, при которых PostgreSQL может эффективно использовать составной индекс.
Обновлено · Команда SQL Arena
Что потренируете
- Читать основные узлы EXPLAIN ANALYZE
- Различать Seq Scan и Index Scan
- Подбирать порядок колонок составного индекса
- Писать sargable-условия
- Проверять, какие строки и страницы реально читает запрос
Пример задачи в тренажёре
Так выглядит задача в SQL Arena: условие, редактор, результат и схема базы.
Для счёта с account_id = 1 получите транзакции за май 2026 года. Верните account_name, created_at и amount. Условие по дате должно оставаться пригодным для работы составного индекса (account_id, created_at): не применяйте функцию к created_at.
SELECT a.account_name, t.created_at, t.amount FROM transactions t JOIN accounts a ON a.id = t.account_id WHERE t.account_id = 1 AND t.created_at >= TIMESTAMP '2026-05-01' AND t.created_at < TIMESTAMP '2026-06-01' ORDER BY t.created_at, t.id;
| # | account_name | created_at | amount |
|---|---|---|---|
| 1 | Northwind | 2026-05-01 08:30:00 | 1400 |
| 2 | Northwind | 2026-05-03 11:15:00 | 900 |
Для счёта с account_id = 1 получите транзакции за май 2026 года. Верните account_name, created_at и amount. Условие по дате должно оставаться пригодным для работы составного индекса (account_id, created_at): не применяйте функцию к created_at.
SELECT a.account_name, t.created_at, t.amount FROM transactions t JOIN accounts a ON a.id = t.account_id WHERE t.account_id = 1 AND t.created_at >= TIMESTAMP '2026-05-01' AND t.created_at < TIMESTAMP '2026-06-01' ORDER BY t.created_at, t.id;
Как читать EXPLAIN ANALYZE и использовать индексы SQL
Индекс создан по (account_id, created_at). Первое условие — точное равенство account_id = 1. После него идёт диапазон по created_at. Такой порядок совпадает с логикой запроса: сначала резко ограничивается один счёт, затем внутри его записей выбирается нужный временной диапазон.
Граница месяца записана как created_at >= '2026-05-01' и created_at < '2026-06-01'. Это sargable-условие: колонка остаётся без функции или преобразования, поэтому оптимизатор может рассматривать индексный диапазон. Запись вроде DATE(created_at) BETWEEN ... меняет выражение над колонкой и без подходящего функционального индекса может лишить запрос удобного индексного пути.
EXPLAIN ANALYZE нужен не для поиска слова Index Scan любой ценой. На маленькой таблице PostgreSQL иногда сознательно выбирает Seq Scan, потому что прочитать её целиком дешевле. В реальной задаче сравнивают фактические строки, стоимость, время, количество циклов и объём работы. Оптимизация начинается с плана, а не с предположения, что каждый запрос обязан использовать индекс.
EXPLAIN показывает план, который оптимизатор выбрал для SQL-запроса, а EXPLAIN ANALYZE дополнительно выполняет запрос и показывает фактические показатели выполнения. При чтении плана важно смотреть не только на наличие Index Scan, но и на объём обработанных строк, условия фильтрации и расхождение оценок с фактическими значениями. Для составного индекса важен порядок колонок. Условия также желательно писать так, чтобы индексируемая колонка не была без необходимости обёрнута функцией или преобразованием.
SELECT a.account_name, t.created_at, t.amount FROM transactions t JOIN accounts a ON a.id = t.account_id WHERE t.account_id = 1 AND t.created_at >= TIMESTAMP '2026-05-01' AND t.created_at < TIMESTAMP '2026-06-01' ORDER BY t.created_at, t.id;
| account_name | created_at | amount |
|---|---|---|
| Northwind | 2026-05-01 08:30:00 | 1400 |
| Northwind | 2026-05-03 11:15:00 | 900 |
Ошибки при оптимизации SQL-запросов и индексов
Функция применяется к индексируемой колонке
Условие DATE(created_at) = DATE '2026-05-01' выглядит удобно, но оно вычисляет выражение для значения колонки. Для обычного индекса по created_at чаще полезнее записать диапазон от начала дня до начала следующего дня.
Составной индекс создаётся в случайном порядке
Индексы (account_id, created_at) и (created_at, account_id) — не одно и то же. Порядок колонок выбирают с учётом реальных условий фильтрации, сортировки и диапазонов. Нельзя просто поставить самой первой колонку с самым понятным названием.
Любой Seq Scan считается проблемой
Последовательное чтение небольшой таблицы может быть оптимальным. Даже на большой таблице Seq Scan бывает правильным, если запрос всё равно возвращает значительную её часть. Сначала нужно понять фактический объём работы по EXPLAIN ANALYZE, а уже потом менять запрос или индекс.
Задачи по теме в тренажёре
Курс SQL PerformanceПрактика оптимизации SQL запросов полезна только тогда, когда приходится принимать решение по плану выполнения. В SQL Arena есть задачи на полный проход журнала, внешний ключ без индекса, выдачу последних заказов и поиск платежей по заказу. На следующем уровне появляются covering index, индексные отчёты и поиск без учёта регистра. Для более последовательной работы есть курс SQL Performance. В нём оптимизация разбирается на базе объёма до 10 млн строк, поэтому разница между полным чтением, индексным доступом и неудачным условием становится заметнее. В интерфейсе доступен EXPLAIN, а решение задачи проходит автопроверку на скрытых данных. Всего SQL Arena содержит 1 192 задачи и отдельные песочницы PostgreSQL, MySQL, ClickHouse и BigQuery.
- EasyбесплатноАварии за сутки: полный проход журналаpostgresql
- EasyбесплатноВнешний ключ без индексаpostgresql
- EasyбесплатноЛента последних заказовpostgresql
- EasyбесплатноПлатежи по заказуpostgresql
- MediumPremiumОтчёт без похода в таблицуpostgresql
- MediumPremiumСчётчик аварий на видном местеpostgresql
- MediumPremiumИндекс, который несёт ответ целикомpostgresql
- MediumPremiumПоиск без учёта регистраpostgresql
Справочник по теме
Подробные статьи с синтаксисом и примерами в справочнике SQL Arena.
Частые вопросы
Что такое индексы SQL?
Индекс — дополнительная структура данных, которая помогает СУБД быстрее находить нужные строки для определённых запросов. Индексы ускоряют не все операции и требуют дополнительного места и работы при изменении данных.
Что показывает EXPLAIN ANALYZE?
EXPLAIN ANALYZE выполняет запрос и показывает выбранный план вместе с фактическими показателями выполнения. Это позволяет сравнивать оценки оптимизатора с реально обработанными строками и временем отдельных операций.
Как выполняется оптимизация SQL-запросов?
Сначала нужно определить, где запрос выполняет лишнюю работу: читать план, оценивать количество строк, соединения, сортировки и фильтры. После этого можно менять запрос, индексы или структуру данных и повторно проверять план.
Что такое EXPLAIN SQL?
EXPLAIN показывает предполагаемый план выполнения SQL-запроса без обычного выполнения самого запроса. В PostgreSQL он отображает операции плана, их стоимость и оценки количества строк.
Что такое план запроса SQL?
План запроса — последовательность операций, выбранных оптимизатором для получения результата. В нём могут присутствовать сканирования таблиц и индексов, соединения, сортировки, агрегации и другие операции.
Практика индексов и оптимизации SQL-запросов
Начните с задач на Seq Scan, Index Scan и простые индексы, затем переходите к составным и покрывающим индексам. Для углублённой практики продолжите в курсе SQL Performance.
Практиковать оптимизацию SQL