Нейросеть для SQL: как писать и оптимизировать запросы с ИИ

Схема, пример данных и план запроса в запросе к модели, проверка через EXPLAIN и доступ только на чтение. Рабочий код на Python и расчёт стоимости.

6 мин · · разработка · API-ключи

Нейросеть для программирования на SQL умеет писать запросы по описанию и объяснять, почему запрос медленный. Но без схемы базы она угадывает имена таблиц, а без проверки может выдать запрос, который работает, но возвращает не то. Хуже всего, если сгенерированный UPDATE или DELETE попадёт в рабочую базу. Ниже порядок работы, который уменьшает эти риски: что передавать модели, как проверять запрос через EXPLAIN и как ограничить доступ.

Пайплайн «вопрос на русском, SQL в ответ» для отчётных интерфейсов разобран в статье генерация SQL запросов нейросетью. Здесь акцент на другом: ежедневная работа разработчика и аналитика, оптимизация и безопасность.

Нейросеть для программирования на SQL: что передавать модели

Запрос «напиши SQL для топ-10 клиентов по выручке» без контекста даст запрос по выдуманным таблицам. Передавайте четыре вещи:

  1. СУБД и версия. PostgreSQL 16, MySQL 8, SQLite: функции дат, оконные функции и LIMIT отличаются.
  2. Схема. Лучше всего подходят CREATE TABLE вместе с ключами, ограничениями и индексами. Модель видит типы и связи.
  3. Несколько строк примера. Две-три обезличенные строки на таблицу. Они показывают формат значений: статусы строками, даты как текст или timestamp, как записаны суммы.
  4. Размеры таблиц. Порядок количества строк. Для оптимизации это важнее, чем кажется: для таблицы на сто строк индекс не нужен.

Выгрузить схему можно штатными средствами вашей СУБД (например, pg_dump --schema-only для PostgreSQL). Не отправляйте реальные данные клиентов: структуры и обезличенных примеров достаточно.

Шаблон запроса

bash
СУБД: PostgreSQL 16.
Схема:
CREATE TABLE orders (id bigint PRIMARY KEY, customer_id bigint NOT NULL,
  status text NOT NULL, created_at timestamptz NOT NULL, total numeric(12,2));
CREATE INDEX orders_customer_idx ON orders (customer_id);
CREATE TABLE customers (id bigint PRIMARY KEY, name text, region text);
Объём: orders около 40 млн строк, customers около 800 тыс.
Статусы: 'new', 'paid', 'cancelled'.

Задача: выручка по регионам за октябрь 2026 по оплаченным заказам.
Требования: только SELECT, границы месяца без BETWEEN по timestamp,
пояснение логики в одном абзаце после запроса.

Две детали, которые экономят правки: явно перечисляйте допустимые значения статусов (иначе модель придумает completed) и просите границы дат в виде >= '2026-10-01' AND < '2026-11-01'. Типичная ошибка с BETWEEN на timestamp теряет последний день.

Проверка: EXPLAIN вместо веры

Читаемый на вид запрос может оказаться полным сканированием 40 миллионов строк. Поэтому у каждого сгенерированного запроса есть этап плана:

  • EXPLAIN показывает план без выполнения запроса. Начинайте с него.
  • EXPLAIN (ANALYZE, BUFFERS) в PostgreSQL выполняет запрос по-настоящему и показывает фактическое время. Для SELECT это безопасно с таймаутом и на реплике, но для запросов, меняющих данные, ANALYZE их выполнит, поэтому такие запросы на нём не гоняйте. Синтаксис и вывод в MySQL и других СУБД отличаются, сверяйтесь с документацией вашей.

Дальше хорошо работает цикл «запрос, план, объяснение»: отправляете модели исходный запрос и вывод плана, просите объяснить узкое место и предложить варианты (перепись запроса, индекс), а затем проверяете каждый вариант на копии базы. Предлагаемый индекс создаёт человек через обычную миграцию, а не скрипт с моделью.

Защита базы: четыре барьера

Код ниже показывает связку барьеров для сгенерированных SELECT-запросов:

bash
import os
import psycopg
import sqlglot
from sqlglot import exp
from openai import OpenAI

client = OpenAI(base_url="https://api.zukko.pro/v1",
                api_key=os.environ["ZUKKO_API_KEY"])

def generate_sql(schema, task):
    resp = client.chat.completions.create(
        model="claude-sonnet-5-5",
        messages=[
            {"role": "system", "content": "Ты помощник по PostgreSQL 16. "

Барьеры по порядку:

  1. Разбор запроса. sqlglot проверяет, что оператор один и это SELECT, а не SELECT 1; DROP TABLE .... Это синтаксическая проверка: побочные эффекты функций она не поймает, поэтому следующий барьер обязателен.
  2. Роль только на чтение. Строка подключения использует пользователя СУБД, у которого есть лишь SELECT на нужные таблицы. Это главный барьер: он работает, даже если все остальные проверки обойдены.
  3. Транзакция только на чтение и таймаут. Запрос не сможет изменить данные и не займёт базу надолго.
  4. Выполнение на реплике или копии. Тяжёлые аналитические запросы не должны мешать рабочей нагрузке.

Если модель просили исправлять данные, это отдельная задача: модель выдаёт скрипт, человек читает, прогоняет на копии, оборачивает в транзакцию и запускает сам.

Типичные ошибки, которые стоит искать

  • Дубли после JOIN. Соединение с таблицей «один ко многим» умножает строки, и SUM выдаёт завышенную сумму.
  • NOT IN с NULL. Подзапрос возвращает NULL, и условие перестаёт срабатывать. Часто нужен NOT EXISTS.
  • Функции другой СУБД. Модель путает DATE_TRUNC, STRFTIME, DATEADD, если не указан диалект.
  • Неявное приведение типов, из-за которого индекс не используется.
  • SELECT * в боевых запросах и сортировка без LIMIT.

Сверяйте результат с контрольными числами: сделайте запрос руками на небольшом срезе и сравните итог. А при оптимизации сравнивайте результаты старого и нового запроса на копии, например, через EXCEPT в обе стороны: пустой результат в обоих направлениях означает совпадающие наборы строк.

Какую модель выбрать

Для простых запросов хватает недорогих моделей, сложную аналитику с оконными функциями и оптимизацию планов стоит прогнать на нескольких. Составьте 15–20 своих запросов с известными ответами и сравните. Цены Zukko на 18 октября 2026 ($ за 1M токенов, вход / выход) и индекс силы:

МодельЦенаИндекс силы
deepseek-v4.1-flash0.013 / 0.03839
gpt-6.1-sol0.27 / 1.3252
claude-sonnet-5-50.4 / 248
claude-opus-5-50.8 / 458

Индекс не измеряет качество SQL именно на вашей схеме, это ориентир. Подборка про выбор модели для кода: лучшая нейросеть для программирования.

Сколько стоит

Формула: (вход × цена входа + выход × цена выхода) / 1 000 000. Допущения: запрос с оптимизацией, 3 000 токенов схемы, 100 токенов вопроса, 800 токенов плана, итого 3 900 токенов входа и 500 токенов выхода.

  • deepseek-v4.1-flash: 3 900 × 0.013 / 1 000 000 + 500 × 0.038 / 1 000 000 = 0.0000507 + 0.000019, около $0.00007.
  • gpt-6.1-sol: 3 900 × 0.27 / 1 000 000 + 500 × 1.32 / 1 000 000 = 0.001053 + 0.00066, около $0.0017.
  • claude-sonnet-5-5: 0.00156 + 0.001, около $0.0026.
  • claude-opus-5-5: 0.00312 + 0.002, около $0.0051.

Двадцать таких запросов в день на claude-sonnet-5-5 это около $0.05. Схема повторяется в каждом запросе, поэтому при частых обращениях выгодно кэшировать её: скидку за кэш для Claude даёт Anthropic-формат, подробности в статье кэширование промптов: чтение и запись. Свежие цены всегда в ответе GET https://api.zukko.pro/v1/models.

Подключение

Создайте ключ в кабинете, укажите base URL https://api.zukko.pro/v1 и подключайтесь по справке chat completions. Баланс пополняется от $1: СБП (платёжная страница добавляет 8,5% сверху), криптовалюта или карта MasterCard.

Частые вопросы

Можно ли дать нейросети доступ к базе напрямую?

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

Как нейросеть для генерации кода SQL узнает схему?

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

Правда ли, что модель оптимизирует запросы?

Она предлагает варианты по плану, который вы ей показали. Эффект проверяется на копии базы, а индекс создаёт человек.

Как проверить, что оптимизированный запрос возвращает то же самое?

Сравните результаты двух запросов на копии через EXCEPT в обе стороны и проверьте итоговые суммы.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.