Генерация SQL-запросов сложной структуры: промт с ER-диаграммой

SQL — один из немногих случаев, где ИИ действительно экономит часы. Написать оконную функцию с правильным фреймом или собрать запрос с четырьмя джойнами и агрегацией по нескольким уровням — задача, где легко ошибиться и долго отлаживать. Модель делает это быстро. При одном условии: она должна знать структуру.
Без схемы происходит предсказуемое: модель придумывает таблицу users с полем created_at, потому что так бывает чаще всего. Запрос выглядит убедительно и не работает.
Как передать схему
Не описывайте словами. Дайте DDL — это самый компактный и точный способ.
Вот структура базы: [вывод SHOW CREATE TABLE для каждой таблицы, или CREATE TABLE из миграций] Дополнительно: - объёмы: [таблица - примерное число строк] - какие поля индексированы: [из DDL видно, но подтверди явно] - СУБД и версия: [PostgreSQL 16 / MySQL 8 / другое] - что означают неочевидные поля: [status = 0 черновик, 1 опубликовано] ЗАДАЧА: [описание нужного результата словами, с примером желаемых строк] ТРЕБОВАНИЯ: - Используй только существующие таблицы и поля. Если чего-то не хватает — скажи, а не придумывай. - Учитывай диалект указанной СУБД. - Объясни выбор типа соединения для каждого JOIN. - Предупреди, если запрос даст дубликаты строк из-за связи «один ко многим».
Предупреждение о дубликатах стоит требовать всегда. Это самая частая и самая тихая ошибка в сложных отчётах: суммы удваиваются, а никто не замечает, пока не сойдутся цифры с бухгалтерией.
Проверка результата
- Сначала COUNT. Запустите с
COUNT(*)вместо полей и без агрегации. Если строк больше, чем ожидали, — размножение по джойну. - Потом LIMIT 20. Глазами посмотрите на данные. Некорректные джойны видны сразу.
- Потом EXPLAIN. Полное сканирование большой таблицы или вложенный цикл по миллионам строк — повод переписать.
- Сверьте с известным числом. Возьмите один день или одного клиента, посчитайте отдельным простым запросом, сравните.
Промт для оптимизации
Вот запрос и его план выполнения: ЗАПРОС: [текст] ПЛАН: [вывод EXPLAIN ANALYZE] ОБЪЁМЫ: [строки в задействованных таблицах] СУЩЕСТВУЮЩИЕ ИНДЕКСЫ: [список] Найди узкие места по плану, а не по виду запроса. Для каждого: что именно дорого, почему, и три варианта решения — переписать запрос, добавить индекс, изменить схему. Для предложенного индекса укажи: по каким полям, в каком порядке, почему такой порядок, и чем этот индекс обойдётся при вставках. Не предлагай индексы, которые дублируют существующие по префиксу.
Требование опираться на план, а не на внешний вид запроса, отсекает советы уровня «замените подзапрос на JOIN» — они часто не дают ничего, а иногда делают хуже.
Что модель делает плохо
- Путает диалекты. Синтаксис оконных функций, работа с датами, конкатенация, upsert — везде различия. Указывайте СУБД и версию явно.
- Оценивает производительность на глаз. Утверждения «этот вариант быстрее» без плана считайте гипотезой.
- Игнорирует NULL. Классическая ловушка:
NOT INс NULL внутри подзапроса возвращает пустоту. Попросите отдельно проверить поведение при NULL в каждом сравнении. - Не знает о блокировках. Запрос, который на тестовой базе летает, на боевой может встать в очередь.
Про ER-диаграмму
Если схема большая, полезно попросить обратное — не запрос из схемы, а схему из запросов: «по этим двадцати запросам восстанови связи между таблицами и нарисуй их в текстовом виде». Так находятся неявные связи, о которых знали только авторы, и места, где внешние ключи существуют в головах, но не в базе. Это, пожалуй, самый недооценённый способ применить ИИ к чужой базе данных.