Почему один и тот же запрос в 1С возвращает разные данные в коде и в консоли запросов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Каждый разработчик на платформе 1С:Предприятие рано или поздно сталкивается с мистической на первый взгляд ситуацией. Вы выполняете запрос в коде программы (например, в режиме отладки), и он возвращает пустой результат. Однако, когда вы копируете этот же самый текст запроса, устанавливаете те же параметры в консоли запросов и запускаете его — консоль возвращает ожидаемые строки данных.

В этой статье мы подробно разберем, почему возникает такое расхождение, рассмотрим внутренние механизмы платформы 1С и СУБД, которые к этому приводят, а также выработаем пошаговый алгоритм поиска и устранения этой проблемы.

Причина №1. Различия в типах пустых параметров запроса

Самая банальная и в то же время частая причина кроется в параметрах запроса. Нам часто кажется, что "пустое" значение — оно и в Африке пустое. Но для СУБД и платформы 1С пустая строка, значение Неопределено, значение NULL и пустая ссылка — это абсолютно разные типы данных с разным поведением.

Рассмотрим пример из практики. В запросе используется параметр &МаскаНомера:


Запрос.Текст = 
    "ВЫБРАТЬ
    |    БНФОНумераторСчетовАналитическогоУчета.Итератор
    |ИЗ
    |    РегистрСведений.БНФОНумераторСчетовАналитическогоУчета КАК БНФОНумераторСчетовАналитическогоУчета
    |ГДЕ
    |    БНФОНумераторСчетовАналитическогоУчета.МаскаНомера = &МаскаНомера";

В отладчике значение переменной выглядит как пустая строка "". Мы предполагаем, что передаем пустую строку. Однако в консоли запросов мы можем не указать тип параметра, и консоль по умолчанию передаст туда Неопределено или вообще исключит этот параметр из типизации, из-за чего СУБД построит совершенно другой план запроса или вернет иной результат сравнения.

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

Чтобы избежать этой проблемы, всегда проверяйте точный тип параметров в отладчике. Для этого в табло отладчика вычисляйте выражение:

ТипЗнч(СтруктураВозврата.КлючНумератора.МаскаНомера)

Если вам необходимо корректно обрабатывать пустые строки и возможные значения NULL в запросе, используйте безопасную конструкцию в тексте запроса:


И (БНФОНумераторСчетовАналитическогоУчета.МаскаНомера = &МаскаНомера 
   ИЛИ БНФОНумераторСчетовАналитическогоУчета.МаскаНомера ПОДОБНО """")

Причина №2. Влияние транзакций и уровней изоляции данных (RCSI)

Если ваш запрос выполняется внутри транзакции (например, при проведении документа, в обработчиках ПередЗаписью или ПриЗаписи модуля объекта/менеджера регистра), то состояние базы данных для этого сеанса будет существенно отличаться от того, что видит консоль запросов.

Разберем этот механизм подробнее:

  1. Очистка перед записью в транзакции. Когда платформа перезаписывает набор записей регистра сведений, она в рамках транзакции сначала полностью удаляет старые записи по регистратору или ключевым полям, а затем записывает новые. Если ваш код с запросом выполняется в процессе записи (например, в модуле менеджера этого же регистра), старые данные уже стерты из таблиц СУБД, а новые еще физически не записаны или не зафиксированы. Запрос в коде вернет пустоту.
  2. Разные сеансы работы с СУБД. Консоль запросов запущена в вашем пользовательском сеансе (в режиме предприятия), а код отладки может выполняться на сервере в фоновом задании или в другой транзакционной сессии. Если на СУБД включен режим Read Committed Snapshot Isolation (RCSI), внешние сеансы (ваша консоль) будут видеть старую ("снимковую") версию данных до тех пор, пока транзакция в коде не завершится успешным коммитом (фиксацией). Из-за этого в консоли вы видите данные, а внутри выполняющегося кода — нет.
  3. Блокировки данных. В СУБД без поддержки RCSI запрос в консоли может просто "зависнуть" на время ожидания блокировки, но если используется режим "грязного чтения" или транзакция успела откатиться при прерывании отладчиком, результаты будут кардинально отличаться.

Проанализируйте стек вызовов в отладчике в момент остановки. Если вы находитесь внутри транзакции записи, помните, что физическая таблица в этот момент находится в промежуточном состоянии.

Причина №3. Ограничения прав доступа на уровне записей (RLS)

Механизм RLS (Row-Level Security) — один из самых частых виновников "исчезновения" данных из запросов в коде.

Представим ситуацию: вы вошли в систему под учетной записью администратора и открыли консоль запросов. Запрос отрабатывает отлично. В то же время отлаживаемый код запускается в контексте обычного пользователя, у которого настроены ограничения прав доступа (например, по организациям или физическим лицам).

Особенность работы RLS в 1С заключается в том, что платформа при нехватке прав доступа на чтение конкретных строк таблицы не выдает никаких ошибок или предупреждений. Она просто "тихо" отфильтровывает эти записи из результата запроса на уровне СУБД.

Выяснить, виновен ли RLS в пустом результате, очень просто. Достаточно временно обернуть выполнение запроса в коде в привилегированный режим, который полностью отключает проверку прав доступа:


УстановитьПривилегированныйРежим(Истина);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

УстановитьПривилегированныйРежим(Ложь);

Если после включения привилегированного режима запрос в коде вернул данные — проблема однозначно в настройках прав доступа и шаблонах RLS для текущего пользователя.

Причина №4. Дубликаты объектов и "битые" ссылки

Иногда визуальное совпадение параметров в консоли и в отладчике является обманчивым из-за существования дублирующихся элементов или повреждения ссылочной целостности базы данных.

Чтобы исключить эту причину, всегда проверяйте уникальные идентификаторы ссылочных параметров в коде и в консоли с помощью метода:

СсылкаНаОбъект.УникальныйИдентификатор()

Сравните полученные строки UUID. Они должны совпадать символ в символ.

Причина №5. Использование кэша платформы и расширений

Платформа 1С:Предприятие активно кэширует данные для оптимизации производительности. При работе с транзакциями кэш на сервере приложений может не успеть обновиться для текущего сеанса отладки.

Кроме того, если в системе установлены расширения конфигурации, они могут неявно модифицировать текст запроса или его параметры "на лету" через механизмы перехвата методов (аннотации &Перед, &Вместо, &После).

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

Пошаговый чек-лист для решения проблемы

Если вы столкнулись с разницей в результатах запроса, рекомендуем пройти по следующему алгоритму:

  1. Выясните точный тип и значение каждого параметра в коде с помощью отладчика. Не полагайтесь на визуальное сходство строк или представлений ссылок.
  2. Проверьте уникальные идентификаторы (UUID) всех ссылочных параметров в коде и в консоли запросов.
  3. Проверьте, не выполняется ли запрос внутри транзакции записи. Попробуйте выполнить аналогичный запрос к тем же данным вне транзакции.
  4. Запустите код под привилегированным режимом, чтобы исключить влияние RLS.
  5. Используйте специализированные инструменты, такие как внешняя обработка "Инструменты разработчика" (ИР). Она позволяет прямо из режима отладки выгрузить объект Запрос со всеми установленными параметрами и открыть его в консоли в том же контексте выполнения, что минимизирует влияние различий в окружении.
← На главную