AIAI University/ Stadika Смотреть курсы
AI University / Промпты / Программисту
Программисту

Промпт: ускорить медленный SQL-запрос по EXPLAIN

Разбор плана выполнения, индексы и переписанный запрос, безопасное создание индекса на проде. Готовый промт на русском: скопируйте, подставьте свои данные и вставьте в GigaChat, YandexGPT, ChatGPT, Claude или Gemini.

Проверено на: GigaChatChatGPTClaudeGemini · Обновлено 01.10.2026

Текст промпта

Ты эксперт по производительности {db}. Помоги ускорить запрос. Запрос: {query} Результат EXPLAIN (ANALYZE, BUFFERS): {explain} Таблицы, объёмы и существующие индексы: {schema}. Дай: 1. Где тратится основное время и почему, со ссылкой на конкретные узлы плана. 2. Варианты ускорения по убыванию эффекта: индексы (готовый DDL), переписанный запрос, изменения схемы. Для каждого: ожидаемый эффект и цена (замедление записи, место на диске, блокировки при создании). 3. Как создать индекс на продакшене без долгой блокировки таблицы. 4. Как проверить результат: какой EXPLAIN запустить и что в нём должно измениться. Не обещай ускорение в конкретное число раз: оценивай качественно.

Что подставить в промт

ПолеПример
{db}PostgreSQL 16
{query}SELECT o.id, o.created_at, o.total, c.email
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'paid'
AND o.created_at >= now() - interval '30 days'
AND lower(c.email) LIKE '%@corp-example.ru'
ORDER BY o.created_at DESC
LIMIT 50;
{explain}Limit (actual time=4812.3..4812.4 rows=50 loops=1)
-> Sort (actual time=4812.3..4812.3 rows=50 loops=1)
Sort Key: o.created_at DESC
Sort Method: top-N heapsort Memory: 32kB
-> Hash Join (actual time=211.5..4806.9 rows=1840 loops=1)
Hash Cond: (o.customer_id = c.id)
-> Seq Scan on orders o (actual time=0.03..4410.7 rows=412000 loops=1)
Filter: ((status = 'paid') AND (created_at >= (now() - '30 days'::interval)))
Rows Removed by Filter: 11588000
-> Hash (actual time=210.9..210.9 rows=3100 loops=1)
-> Seq Scan on customers c (actual time=0.02..209.8 rows=3100 loops=1)
Filter: (lower(email) ~~ '%@corp-example.ru'::text)
Rows Removed by Filter: 896900
Planning Time: 0.9 ms
Execution Time: 4812.9 ms
Buffers: shared hit=18211 read=402377
{schema}orders: 12 млн строк, индексы PK(id) и (customer_id); customers: 900 тыс. строк, индексы PK(id) и unique(email); статусы заказов new, paid, shipped, cancelled, доля paid около 30%, за последние 30 дней около 3% заказов

Ответы нейросетей на этот промпт

Один и тот же промпт с примером выше, ответы без правок: выберите нейросеть, которой пользуетесь, и посмотрите, что она выдаёт.

GigaChat 2 Max06.10.2026
Анализ текущего запроса и планового вывода

Проблема №1:
Основной источник медленной работы — последовательный сканирование (Seq Scan) таблиц orders и customers.

Проблема №2:
Сортировка порядка выполнения запроса происходит по дате заказа (o.created_at DESC), что требует полной сортировки найденных результатов перед ограничением LIMIT до первых 50 записей. Если бы была возможность отфильтровывать данные раньше и сразу получать отсортированные результаты, процесс мог бы стать значительно быстрее.


Решение проблемы: варианты оптимизации по эффективности
1️⃣ Создание композитного индекса с учетом всех условий WHERE и ORDER BY

Наиболее эффективный способ повысить производительность данного запроса — создание специального композитного индекса, который учитывает порядок фильтрации и сортировки одновременно.

CREATE INDEX idx_orders_status_created_email ON orders(status, created_at DESC);

Ожидаемый эффект: Этот индекс позволит быстро найти нужные заказы за последний месяц со статусом "paid". После быстрого поиска нужных записей дальнейшая сортировка будет происходить уже среди небольшого числа отобранных строк, что резко снизит затраты на обработку данных. Индекс включает поле created_at, необходимое для сортировки, что устраняет необходимость отдельной операции сортировки.

Цена решения:

2️⃣ Оптимизация условия поиска по email через функциональный индекс

Следующая проблема — условие LOWER(email) сильно замедляет работу запросов, поскольку PostgreSQL не может использовать обычный индекс при применении функции над колонкой. Можно решить эту проблему созданием дополнительного индекса на преобразованное значение поля.

CREATE INDEX idx_customers_lower_email ON customers(LOWER(email));

Ожидаемый эффект: Позволяет избежать полного просмотра таблицы customers при поиске нужного диапазона адресов электронной почты. Это приведет к быстрому поиску подходящих клиентов.

Цена решения:

3️⃣ Рефакторинг запроса (если невозможно добавить индексы)

Если по каким-то причинам нельзя изменить структуру индексов, можно попробовать немного улучшить существующий запрос. Например, выборка из customers должна идти первой, чтобы уменьшить количество кандидатов на сопоставление в orders.

SELECT o.id, o.created_at, o.total, c.email
FROM (
   SELECT id, LOWER(email) AS lower_email
   FROM customers
   WHERE LOWER(email) LIKE '%@corp-example.ru'
 ) c
JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'paid'
AND o.created_at >= NOW() - INTERVAL '30 DAYS'
ORDER BY o.created_at DESC
LIMIT 50;

Ожидаемый эффект: Такой подход потенциально поможет несколько сократить объем обработки, но кардинального улучшения ожидать не стоит, так как база всё равно вынуждена делать полное сканирование обоих таблиц.

Цена решения: Отсутствует дополнительная нагрузка на базу данных, кроме минимальных накладных расходов на дополнительную вложенную операцию.


Быстрое создание индекса на production-сервере

Чтобы минимизировать блокировку таблицы во время создания большого индекса на продакшн-системе, рекомендуется использование команды CREATE INDEX CONCURRENTLY. Она позволяет создавать индекс асинхронно и практически не блокирует параллельные запросы на запись.

CREATE INDEX CONCURRENTLY idx_orders_status_created_email ON orders(status, created_at DESC);
CREATE INDEX CONCURRENTLY idx_customers_lower_email ON customers(LOWER(email));

Преимущества: Минимальное влияние на доступ пользователей и приложений. Нет длительной блокировки.

Недостаток: Создается чуть дольше обычного индекса, потребляя больше ресурсов системы.


Проверка результата

После внесения изменений нужно заново проанализировать план выполнения запроса командой EXPLAIN ANALYZE:

EXPLAIN (ANALYZE, BUFFERS)
SELECT o.id, o.created_at, o.total, c.email
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'paid'
AND o.created_at >= now() - interval '30 days'
AND lower(c.email) LIKE '%@corp-example.ru'
ORDER BY o.created_at DESC
LIMIT 50;

Что должно измениться в выводе:


Таким образом, оптимизированный запрос с новыми индексами обеспечит значительное повышение производительности и устранит основные узкие места текущей реализации.

Советы

Как пользоваться
  1. Скопируйте промпт кнопкой выше.
  2. Замените поля в фигурных скобках своими данными.
  3. Отправьте в нейросеть и сравните ответ с примером на этой странице.

Подробнее о структуре хорошего запроса: гид AI University.

Похожие промпты

ПрограммистуБесплатно Найти причину ошибки по стектрейсу и логамВероятная причина плавающей ошибки, гипотезы с проверками, исправление и защита от повторения. 4 ответаОткрытьПрограммистуБесплатно Ревью pull request по diffРевью изменений с приоритетами: блокирующие ошибки, безопасность, тесты, готовые комментарии. 4 ответаОткрытьПрограммистуС доступом Миграция базы данных без простояПлан изменения схемы по шагам expand и contract, миграции, перенос данных батчами и откат. 4 ответаСмотреть ответы

Все 435 промптов и 6 наборов

172 промптов открыты бесплатно. Остальные и наборы-цепочки открывает доступ к библиотеке за 1 490 ₽. Полный доступ за 4 900 ₽: все курсы AI University на русском и библиотека промптов. Разовый платёж, новые промпты входят.