Почему запрос к виртуальной таблице ОстаткиИОбороты с периодичностью ДЕНЬ возвращает пустые даты или разные результаты на 1С 8.3?

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

При переводе старых конфигураций 1С (например, разработанных на обычных формах или использующих устаревшие режимы совместимости) на современную платформу 1С:Предприятие 8.3 разработчики часто сталкиваются с крайне загадочным поведением запросов. Типичный сценарий: простой и годами отлаженный запрос к виртуальной таблице ОстаткиИОбороты с периодичностью ДЕНЬ начинает возвращать пустые даты вида 01.01.0001 в поле периода, либо выдает результаты, кардинально отличающиеся от того, что система выдавала на платформе 8.2.

Особенно сильно запутывает то, что на тестовой базе (где сервер СУБД и сервер приложений установлены на одном компьютере) все может работать идеально, но как только конфигурация переносится в рабочую многосерверную среду, отчеты и обработки начинают выводить пустые строки или ломать логику расчетов. В этой статье мы подробно разберем, почему возникает этот сбой, проанализируем физику взаимодействия платформы с Microsoft SQL Server и рассмотрим пошаговый алгоритм полного устранения проблемы.

Симптомы проблемы: как проявляется сбой

Давайте проанализируем типичные проявления этой ошибки на уровне разработки и администрирования:

  1. При выполнении запроса к виртуальным таблицам ОстаткиИОбороты или Обороты с использованием периодичности ДЕНЬ, МЕСЯЦ или ГОД, возвращаемое поле периода (например, ПериодДень) содержит пустое значение даты — 01.01.0001.
  2. Если изменить периодичность виртуальной таблицы в запросе на ЧАС, РЕГИСТРАТОР или ЗАПИСЬ, проблема мгновенно исчезает, и даты начинают выбираться корректно.
  3. Тестирование и исправление информационной базы, реструктуризация таблиц через конфигуратор, а также полный пересчет итогов регистров накопления либо не помогают вовсе, либо приносят лишь временный результат до первой перезагрузки служб.
  4. Проблема имеет выраженный «серверный» характер. На локальных файловых копиях или на тестовом сервере «все в одном» запрос отрабатывает штатно, но на рабочем распределенном кластере стабильно выдает пустые даты.

Рассмотрим классический пример запроса, который подвержен этой уязвимости:


ВЫБРАТЬ
    ПродажиОбороты.ПериодДень КАК ПериодДень,
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.КоличествоОборот КАК КоличествоОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПродажиОбороты

На проблемном сервере колонка ПериодДень в результате выполнения этого пакета будет полностью незаполнена, хотя сами движения и аналитика по номенклатуре выберутся верно.

Глубинные технические причины: почему ломаются даты?

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

Начиная с режима совместимости 8.3.6, платформа 1С кардинально меняет подход к работе с типами данных даты и времени в SQL-запросах. Вместо стандартного и устаревшего типа данных datetime (который использовался в 8.2 и ранних версиях 8.3) платформа начинает активно использовать тип данных datetime2. Этот тип обладает более высокой точностью и расширенным диапазоном дат.

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

Именно на стыке работы с временными таблицами tempdb возникает конфликт драйверов:

Это объясняет, почему на тестовом сервере «все в одном» все работало: при установке MS SQL Server на компьютер автоматически устанавливается и актуальный Native Client. Процесс rphost использует его по умолчанию. На выделенном же сервере 1С администраторы часто забывают установить клиентскую часть SQL, оставляя сервер приложений без необходимых драйверов.

Пошаговая инструкция по решению проблемы

Для окончательного устранения этого сбоя необходимо обновить программное окружение сервера приложений 1С и правильно переинициализировать подключение к базе данных. Разберем этот процесс по шагам.

Шаг 1. Установка правильного драйвера СУБД на сервере 1С

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

Шаг 2. Перерегистрация базы данных в кластере 1С

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

Для того чтобы принудить платформу использовать только что установленный Native Client, выполните следующие действия:

  1. Откройте утилиту Администрирование серверов 1С Предприятия.
  2. Найдите вашу рабочую информационную базу в списке.
  3. Запишите или сфотографируйте все параметры подключения (имя сервера СУБД, имя базы данных, имя пользователя SQL).
  4. Нажмите правой кнопкой мыши по информационной базе и выберите команду Удалить.
  5. В появившемся диалоговом окне критически важно выбрать пункт «Оставить информационную базу без изменений» (это сохранит саму базу данных на SQL-сервере и удалит лишь регистрационную запись из кластера 1С).
  6. Нажмите правой кнопкой мыши на ветку «Информационные базы» и выберите Создать -> Информационная база.
  7. Введите ранее записанные параметры подключения и зарегистрируйте базу заново под тем же именем.

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

Шаг 3. Сброс процедурного кэша СУБД

В редких случаях в оперативной памяти SQL-сервера могут кэшироваться неверные планы запросов к tempdb. Чтобы окончательно исключить влияние старых трансляций, рекомендуется запустить среду SQL Server Management Studio (SSMS) и выполнить команду очистки процедурного кэша для вашей базы данных:


USE [ИмяВашейБазыДанных];
GO
DBCC FREEPROCCACHE;
GO

После выполнения этих шагов все запросы к виртуальным таблицам с периодичностью ДЕНЬ начнут возвращать корректные значения дат.

Альтернативные обходные пути на уровне кода

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

Прием 1. Использование альтернативной периодичности. Если бизнес-логика отчета позволяет, измените периодичность виртуальной таблицы с ДЕНЬ на РЕГИСТРАТОР или ЗАПИСЬ. В этом случае платформа строит принципиально иные SQL-запросы без промежуточного усечения дат во временных таблицах:


// Вместо периодичности "День" используем "Регистратор"
// и в самом запросе получаем дату документа-регистратора
ВЫБРАТЬ
    ПродажиОбороты.ПериодСекунда КАК Период,
    НАЧАЛОПЕРИОДА(ПродажиОбороты.ПериодСекунда, ДЕНЬ) КАК ПериодДень,
    ПродажиОбороты.Номенклатура,
    ПродажиОбороты.КоличествоОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(, , Авто, ) КАК ПродажиОбороты

Прием 2. Перенос условий связи. Избегайте использования функции НАЧАЛОПЕРИОДА внутри условий связи таблиц (секция ПО). Некорректный драйвер SQL чаще всего ломает логику дат именно при операциях соединения таблиц по вычисляемым датам. Выносите предварительные расчеты дат во временные таблицы пакета запросов, а соединение делайте по уже готовым проиндексированным полям.

← На главную