Oracle SQL-скрипты, созданные LLM-агентами, могут выглядеть безупречно на бумаге, но при этом приводить к сбоям в продакшене. В устаревшей кодовой базе объемом 2,3 миллиона строк AI-агент регулярно допускал ошибки в идентификаторах — например, использовал POLICY_STATUS вместо существующей колонки STATUS_CD или ссылался на несуществующую таблицу CUSTOMERS вместо CUSTOMER.

Запуск скрипта для поиска опечатки — не вариант для операторов UPDATE или DELETE. Их выполнение на наборе данных, имитирующем продуктивную среду, приводит к блокировкам, расходу значений последовательностей и может вызвать каскадные побочные эффекты. Разработчикам нужен способ проверять имена и синтаксис, не затрагивая данные. Ответ, на удивление простой, заключается в использовании команды Oracle EXPLAIN PLAN, переосмысленной как этап линтинга.

Как EXPLAIN PLAN работает в качестве быстрого валидатора

Когда Oracle получает оператор, он сначала выполняет его парсинг. Парсинг проверяет наличие всех упомянутых таблиц, колонок и прав доступа, затем строит план выполнения и записывает этот план в системную таблицу. Команда никогда не выполняет сам оператор: строки не изменяются, триггеры не срабатывают, блокировки не устанавливаются. Если парсер натыкается на неизвестный объект, он выдает ошибку за несколько миллисекунд.

Такое поведение делает EXPLAIN PLAN идеальным инструментом для предварительной проверки SQL-кода, сгенерированного ИИ. О пропущенной таблице или колонке сообщается мгновенно, что позволяет циклу генерации исправить ошибку еще до того, как скрипт увидит человек.

Рабочий процесс, который я встроил в свой CI-конвейер

  1. Разбить входящий скрипт на отдельные операторы.
  2. Запустить EXPLAIN PLAN FOR <statement> в схеме разработки.
  3. Собрать все ошибки парсинга, которые вернет Oracle.
  4. Передать ошибки обратно в LLM для повторной попытки.

На практике одна повторная попытка исправляет большинство ошибок в именовании. ИИ изучает правильную схему и автоматически корректирует свой вывод. Я также ограничиваю агента режимом «только для чтения»: он может выполнять SELECT и вызовы EXPLAIN PLAN, но операции DDL, DML и COMMIT заблокированы. Такой «песочница» гарантирует, что база данных останется нетронутой, пока ИИ исследует её структуру.

Помимо проверки имен, сгенерированный план выявляет очевидные проблемы с производительностью. Если оператор вызовет полное сканирование таблицы (full-table scan) на огромном массиве данных, план покажет это еще до того, как будут затронуты какие-либо строки, давая разработчикам возможность предложить индексы или переписать предикат.

Ограничения подхода

  • Логическая корректность не проверяется. Оператор, который ссылается на правильные колонки, но применяет неверный фильтр, все равно пройдет линтинг.
  • Блоки PL/SQL не входят в область охвата. Парсер обрабатывает только отдельные SQL-операторы; процедурный код требует отдельного пути валидации.
  • Отсутствует валидация на уровне данных. Линтер не может сказать, соответствует ли литеральное значение домену колонки или действительно ли существует ссылка на внешний ключ.
  • Только dev-схема. Ошибки, возникающие только в продакшене — например, таблица, которая есть в dev, но переименована в prod — остаются невидимыми до определенного момента.

Эти пробелы не уменьшают полезность метода; они просто определяют его границы. Для большинства DML-скриптов, созданных LLM, наиболее распространенным типом ошибки является опечатка или неверное имя объекта, и именно это ловит EXPLAIN PLAN.

Переносимость на другие СУБД

Тот же принцип применим и к другим базам данных. Оператор PREPARE или EXPLAIN в PostgreSQL позволяет распарсить запрос без его выполнения. SQL Server предлагает SET PARSEONLY ON, что заставляет движок проверять синтаксис и имена объектов, пропуская фактическую обработку. Любая СУБД, разделяющая парсинг и выполнение, может стать легковесным шлюзом для линтинга.

Итог

Запуск EXPLAIN PLAN (или его эквивалента) для каждого SQL-оператора, созданного ИИ, превращает парсер базы данных в недорогой и безрисковый инструмент линтинга. Он отлавливает наиболее частые ошибки в именах и синтаксисе до того, как будут затронуты какие-либо данные, сохраняя стабильность legacy-систем и позволяя разработчикам пользоваться преимуществами продуктивности при написании кода с помощью LLM.