SQL, но без боли: 15 промтов, которые заменят DBA в вашей команде
Вы когда-нибудь просыпались в 3 часа ночи от мысли: «Почему мой запрос работает 40 секунд?»? Я — да. После того как я однажды случайно положил прод-базу на 10 минут, я понял: пора делегировать рутину нейросетям. Теперь я общаюсь с базой через промты, и она (почти) не обижается.
Эта подборка — не сборник «магических заклинаний», а рабочие инструменты для аналитиков и бэкенд-разработчиков. Каждый промт решает конкретную задачу: от генерации сложных JOIN до проектирования схемы. Проверено на PostgreSQL, MySQL и ClickHouse в бою.
1. Генерация запроса по описанию на естественном языке
Задача: превратить словесное описание в рабочий SQL.
Напиши SQL-запрос для PostgreSQL, который выводит топ-10 клиентов по сумме заказов за последний месяц. Таблицы: customers(id, name), orders(id, customer_id, amount, created_at). Учитывай только оплаченные заказы (status = 'paid').
Пример использования:
SELECT c.name, SUM(o.amount) AS total
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.created_at >= date_trunc('month', CURRENT_DATE) - INTERVAL '1 month'
AND o.status = 'paid'
GROUP BY c.id, c.name
ORDER BY total DESC
LIMIT 10;
2. Оптимизация существующего запроса через EXPLAIN
Задача: найти узкие места в медленном запросе.
Вот EXPLAIN ANALYZE моего запроса. Найди проблему и предложи оптимизацию (индексы, переписывание). Запрос: SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC LIMIT 20;
Пример использования:
Объяснение: планировщик использует Seq Scan по orders, потому что нет индекса на customer_id. Рекомендация: CREATE INDEX idx_orders_customer_created ON orders(customer_id, created_at DESC);
3. Проектирование схемы БД для нового сервиса
Задача: спроектировать таблицы под описанный функционал.
Спроектируй схему для интернет-магазина: товары, категории, заказы, пользователи. Учитывай связи многие-ко-многим, внешние ключи, индексы. Дай DDL для PostgreSQL.
Пример использования:
CREATE TABLE categories (id SERIAL PRIMARY KEY, name TEXT NOT NULL);
CREATE TABLE products (id SERIAL PRIMARY KEY, category_id INT REFERENCES categories(id), name TEXT NOT NULL, price NUMERIC(10,2));
CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT UNIQUE NOT NULL);
CREATE TABLE orders (id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id), created_at TIMESTAMP DEFAULT NOW());
CREATE TABLE order_items (order_id INT REFERENCES orders(id), product_id INT REFERENCES products(id), quantity INT CHECK (quantity > 0), PRIMARY KEY (order_id, product_id));
4. Написание миграций с откатом
Задача: создать безопасную миграцию для изменения схемы.
Напиши миграцию для добавления колонки discount NUMERIC(5,2) DEFAULT 0 в таблицу products. Дай версию для PostgreSQL с условием IF NOT EXISTS и откатом.
Пример использования:
-- Up
ALTER TABLE products ADD COLUMN IF NOT EXISTS discount NUMERIC(5,2) DEFAULT 0;
-- Down
ALTER TABLE products DROP COLUMN IF EXISTS discount;
5. Перевод запроса между диалектами SQL
Задача: адаптировать запрос из PostgreSQL в MySQL или ClickHouse.
Переведи этот запрос из PostgreSQL в ClickHouse: SELECT customer_id, COUNT(*) FROM orders WHERE created_at >= NOW() - INTERVAL '7 days' GROUP BY customer_id;
Пример использования:
SELECT customer_id, count() FROM orders WHERE created_at >= now() - INTERVAL 7 DAY GROUP BY customer_id;
6. Генерация тестовых данных
Задача: создать набор синтетических данных для проверки.
Сгенерируй SQL для вставки 1000 тестовых записей в таблицу users(email, name, created_at). Используй generate_series для PostgreSQL.
Пример использования:
INSERT INTO users (email, name, created_at)
SELECT 'user'
|| i || '@test.com', 'User ' || i, NOW() - (i || ' days')::interval
FROM generate_series(1, 1000) AS i;
7. Анализ производительности через EXPLAIN ANALYZE
Задача: получить разбор выполнения запроса.
Дай команду EXPLAIN ANALYZE для этого запроса и объясни, что означает каждая часть вывода: SELECT * FROM orders WHERE amount > 100;
Пример использования:
EXPLAIN ANALYZE SELECT * FROM orders WHERE amount > 100;
Результат: Seq Scan on orders (cost=0.00..35.50 rows=5 width=36) (actual time=0.024..0.038 rows=5 loops=1)
Объяснение: cost — оценка затрат, rows — число строк, actual time — реальное время.
8. Оптимизация JOIN и подзапросов
Задача: улучшить сложный запрос с несколькими JOIN.
Этот запрос с тремя JOIN работает медленно: SELECT ... FROM a JOIN b ON ... JOIN c ON ... WHERE a.type = 'x'. Предложи альтернативу с EXISTS или CTE.
Пример использования:
-- Было
SELECT DISTINCT a.id FROM a JOIN b ON a.id = b.a_id JOIN c ON b.id = c.b_id WHERE c.status = 'active';
-- Стало
SELECT a.id FROM a WHERE EXISTS (SELECT 1 FROM b JOIN c ON c.b_id = b.id WHERE b.a_id = a.id AND c.status = 'active');
9. Работа с оконными функциями
Задача: написать запрос с ROW_NUMBER, LAG, SUM(OVER) для аналитики.
Напиши запрос для PostgreSQL: для каждого клиента выведи его заказы с порядковым номером по дате и разницей в днях между соседними заказами. Таблицы: orders(id, customer_id, created_at).
Пример использования:
SELECT customer_id, id, created_at,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY created_at) AS rn,
created_at - LAG(created_at) OVER (PARTITION BY customer_id ORDER BY created_at) AS days_diff
FROM orders;
10. Диагностика блокировок и взаимоблокировок
Задача: найти и решить проблему с блокировками в PostgreSQL.
Дай запрос для поиска активных блокировок в PostgreSQL и объясни, как их снять.
Пример использования:
SELECT pid, state, wait_event_type, wait_event, query
FROM pg_stat_activity
WHERE state = 'active' AND wait_event_type IS NOT NULL;
-- Для принудительного завершения: SELECT pg_terminate_backend(pid);
11. Генерация отчёта с группировкой по периодам
Задача: создать отчёт по продажам с группировкой по дням/неделям/месяцам.
Напиши запрос для ClickHouse: количество заказов и сумма выручки по дням за последние 30 дней. Таблица: orders(created_at DateTime, amount Decimal).
Пример использования:
SELECT toDate(created_at) AS day, count() AS orders, sum(amount) AS revenue
FROM orders
WHERE created_at >= now() - INTERVAL 30 DAY
GROUP BY day
ORDER BY day;
12. Объяснение плана выполнения запроса
Задача: понять, что делает планировщик.
Объясни этот план выполнения простыми словами: 'Index Scan using idx_orders_customer on orders (cost=0.28..8.30 rows=1 width=12)'.
Пример использования:
Это означает, что PostgreSQL использует индекс idx_orders_customer для поиска строк по customer_id, что эффективнее полного сканирования. cost — относительная оценка затрат, rows — ожидаемое число строк.
13. Написание функции или хранимой процедуры
Задача: создать функцию для повторяющегося расчёта.
Создай функцию в PostgreSQL: calculate_discount(price NUMERIC, user_rank TEXT), которая возвращает цену со скидкой: 'gold' — 20%, 'silver' — 10%, иначе 0.
Пример использования:
CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, user_rank TEXT)
RETURNS NUMERIC AS $$
BEGIN
RETURN price * CASE user_rank WHEN 'gold' THEN 0.8 WHEN 'silver' THEN 0.9 ELSE 1 END;
END;
$$ LANGUAGE plpgsql;
14. Выявление дубликатов и аномалий в данных
Задача: найти повторяющиеся записи или некорректные значения.
Напиши запрос для поиска дубликатов email в таблице users, оставив только один ID для каждого дубликата.
Пример использования:
SELECT email, COUNT(*) AS cnt, array_agg(id) AS ids
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
-- Удаление дубликатов: DELETE FROM users WHERE id NOT IN (SELECT MIN(id) FROM users GROUP BY email);
15. Рекомендации по индексации
Задача: понять, какие индексы нужны для ускорения запросов.
Вот типичные запросы к таблице events: WHERE user_id = ? AND created_at > ? ORDER BY created_at DESC. Какие индексы посоветуешь?
Пример использования:
CREATE INDEX idx_events_user_created ON events(user_id, created_at DESC);
-- Покрывающий индекс, если нужно только эти колонки:
CREATE INDEX idx_events_user_created_covering ON events(user_id, created_at DESC) INCLUDE (event_type);
Как я использовал эти промты в реальной работе
Недавно мне нужно было выгрузить данные о поведении пользователей за год. Запрос с тремя JOIN выполнялся 15 секунд. Я скормил его промту №2, получил рекомендацию по индексу, создал его через миграцию (промт №4) — время упало до 0.2 секунды. Сэкономил себе час ожидания и нервов.
Для ClickHouse я использую промт №11 для ежедневных отчётов — он генерирует точные запросы с учётом синтаксиса, а не «примерно похожие». Это критично, потому что ClickHouse не поддерживает стандартный SQL на 100%.
Пять правил безопасного использования промтов
- Всегда проверяй на копии базы. Промты могут предлагать DROP TABLE или DELETE без WHERE.
- Уточняй версию СУБД. PostgreSQL 16 и MySQL 8 имеют разные синтаксисы для одних и тех же задач.
- Используй EXPLAIN до выполнения. Попроси нейросеть сразу выдать план.
- Не доверяй слепо. Сверяй с документацией: PostgreSQL, ClickHouse.
- Изолируй права. Для промтов, которые меняют данные, используй отдельного пользователя с ограниченными правами.
Что дальше
Соберите свою библиотеку промтов — я сохранил эти 15 в заметки и добавляю новые по мере появления задач. Начните с трёх самых частых: генерация (№1), оптимизация (№2), и индексы (№15). Они закрывают 80% ежедневных потребностей.
Если хотите научиться составлять такие промты системно, на платформе Asibiont есть курсы по работе с ИИ в разработке — но это уже другая история. Пока просто скопируйте промт, вставьте в ChatGPT или Claude, и ваша база скажет вам спасибо.
А какой запрос вы мечтаете оптимизировать? Напишите в комментариях — обсудим.
Comments