Ситуация, когда расчеты в 1С ведут себя по-разному в зависимости от режима работы базы данных (файловый или клиент-серверный), является одной из самых сложных для диагностики. Часто пользователи сталкиваются с тем, что при расчете страховых взносов в клиент-серверном варианте на базе MS SQL Server в отчетах появляются «кривые» цифры или расхождения в несколько копеек, в то время как при выгрузке этой же базы в файловый вариант (через .dt) суммы становятся корректными. В этой статье мы подробно разберем, почему это происходит, проанализируем влияние настроек СУБД на математические вычисления и выясним, как устранить подобные расхождения.
Для начала проанализируем фундаментальную разницу в том, как выполняются расчеты. В файловом варианте за все вычисления отвечает внутренний движок платформы 1С. Он выполняет арифметические операции строго последовательно, используя внутренние алгоритмы округления, заложенные разработчиками конфигурации. В этом режиме код Округлить(Сумма * Ставка, 2) отрабатывает предсказуемо на каждом этапе.
В клиент-серверном варианте ситуация меняется. Платформа 1С транслирует запросы (особенно в отчетах на СКД или при работе с виртуальными таблицами итогов) в диалект T-SQL. Часть вычислений, включая агрегацию SUM(), перекладывается на сторону MS SQL Server. Рассмотрим подробнее, к чему это приводит:
Numeric или Decimal часто использует промежуточную повышенную точность (до 6-38 знаков после запятой). Если итоговое округление до 2-х знаков происходит только в самом конце выполнения запроса над всей выборкой, возникает накопительная погрешность.tempdb для создания временных таблиц. Если в конфигурации типы ресурсов определены неявно, SQL может назначить им типы с плавающей точкой (например, float), что по определению ведет к потере точности при суммировании больших массивов данных.Выясним причину наиболее частого расхождения в страховых взносах, которое упоминается в официальных баг-трекерах 1С под номером 10223536. Эта проблема специфична для организаций, применяющих льготные тарифы для малого и среднего предпринимательства (МСП).
Суть проблемы заключается в алгоритме распределения базы взносов. Когда доход сотрудника превышает МРОТ, база делится на две части: облагаемую по основному тарифу (22%) и облагаемую по пониженному тарифу (10%). В клиент-серверном варианте при формировании виртуальных таблиц итогов SQL-запрос может некорректно интерпретировать приоритет операций. В результате взносы могут распределяться с ошибкой в 1-2 копейки. Рассмотрим пример логики, которая может приводить к ошибке:
// Упрощенный пример логики в SQL, которая может давать сбой
SELECT
SUM(ROUND(BasePart1 * Rate1, 2)) as Tax1,
SUM(ROUND(BasePart2 * Rate2, 2)) as Tax2
FROM CalculationTable
Если округление внутри функции SUM отрабатывает иначе, чем в коде 1С при записи в регистры, мы получаем расхождение между данными в регистрах и данными, которые «на лету» вычисляет отчет.
Проанализируем ситуацию с версиями программного обеспечения. Опыт показывает, что проблема часто проявляется на специфических версиях MS SQL Server (например, 2008 без сервис-паков или 2014 без кумулятивных обновлений). Важнейшим параметром здесь является Compatibility Level (уровень совместимости базы данных).
Если ваша база работает на MS SQL Server 2014, но имеет уровень совместимости 120, попробуйте изменить его. Иногда перевод базы в режим совместимости со старыми версиями (например, 110 — SQL 2012) меняет логику работы оптимизатора запросов и математического процессора SQL, что устраняет проблему с округлением без изменения кода программы.
Также стоит обратить внимание на регламентные операции. В файловом варианте при выгрузке/загрузке .dt все итоги пересчитываются принудительно. В SQL-варианте данные могут «застревать» в физических таблицах итогов. Если регламентное задание Пересчет итогов не выполнялось долгое время, отчеты могут показывать неверные данные, отличные от тех, что мы видим в документах.
Разберем по шагам, что необходимо сделать для устранения разницы в суммах:
.cfe), которые принудительно заставляют сервер выполнять округление на каждом промежуточном этапе расчета.tempdb была оптимизирована.Numeric Round-Abort в настройках сервера. Также убедитесь, что база данных не находится в режиме ограниченного доступа, который может мешать обновлению статистик.Посмотрим на ситуацию с точки зрения кода. Если вы разрабатываете собственный отчет или запрос, старайтесь явно приводить типы к нужной точности. Например, вместо простого деления в запросе используйте конструкцию ВЫРАЗИТЬ:
ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Сумма * 0.15 КАК ЧИСЛО(15, 2)) КАК СуммаНалога
ИЗ
РегистрНакопления.ЗарплатаКВыплате КАК Таблица
Это гарантирует, что MS SQL Server применит фиксированную точность Numeric(15, 2) при формировании результирующего набора данных, что минимизирует риск возникновения «хвостов» в копейках.
Подводя итог, можно сказать, что проблема расхождения сумм в файловом и SQL вариантах — это результат сложного взаимодействия механизмов трансляции запросов 1С и математического ядра СУБД. Сочетание обновления программного обеспечения и правильной настройки итогов позволяет полностью избавиться от этой ошибки.