Каждый практикующий специалист 1С или опытный бухгалтер рано или поздно сталкивается со странным поведением отчетов по регистру бухгалтерии. При формировании стандартных отчетов (например, «Карточки счета» или «Оборотно-сальдовой ведомости») система внезапно выдает предупреждение: «В отчете расходятся суммы остатков и оборотов. Рекомендуется пересчитать итоги». Ситуация становится еще более загадочной, когда при сравнении результатов запросов к виртуальным таблицам Остатки и ОстаткиИОбороты мы получаем разное количество строк или разные суммы по одной и той же номенклатурной позиции.
В этой статье мы подробно разберем, почему возникает эта ошибка на уровне базы данных, что представляют собой так называемые «бабочки» в субконто, почему бухгалтерам не стоит бояться пересчета итогов и какими способами можно быстро и безопасно исправить ситуацию даже на огромных терабайтных базах данных.
Чтобы понять первопричину сбоя, заглянем «под капот» платформы 1С:Предприятие 8.3. На уровне СУБД (будь то Microsoft SQL Server, PostgreSQL или файловая база) регистр бухгалтерии Хозрасчетный состоит не из одной таблицы, а из целого семейства физических таблиц. Основными для нашего анализа являются две:
_AccRg). В ней хранятся первичные документы, их проводки, реальные даты, счета, субконто, суммы и количества. Это единственный источник абсолютной истины в системе._AccRgT). Это вспомогательная таблица агрегатов. В ней хранятся рассчитанные остатки и обороты на начало каждого месяца. Она нужна исключительно для ускорения работы системы, чтобы при формировании отчетов за текущий день 1С не пересчитывала все проводки, начиная с 2000 года, а брала готовую «сводную» цифру на начало текущего месяца и быстро добавляла к ней движения за оставшиеся дни.Когда мы обращаемся к различным виртуальным таблицам регистра бухгалтерии, платформа строит SQL-запросы по совершенно разным алгоритмам:
РегистрБухгалтерии.Хозрасчетный.Остатки платформа считывает предварительно рассчитанные данные напрямую из вспомогательной таблицы итогов (кэша) на ближайшую дату и «докручивает» к ним движения из таблицы проводок.РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты платформа вынуждена использовать более сложный механизм связи, задействуя как таблицы остатков, так и таблицу движений (проводок) для динамического вычисления оборотов за выбранный интервал.Если в силу каких-то причин (аварийное завершение работы СУБД, динамическое обновление конфигурации, сбои транзакций или программные ошибки платформы) кэш в таблице итогов повреждается или рассчитывается неверно, возникает рассинхронизация. Таблица итогов начинает жить своей жизнью, а таблица движений — своей. В результате запрос к Остатки выдает поврежденные закэшированные данные, а запрос к ОстаткиИОбороты возвращает корректные цифры, собранные напрямую из первичных проводок. Именно эту разницу и фиксирует стандартный отчет, выдавая предупреждение пользователю.
Проанализируем классический сценарий, упомянутый в обсуждении: в прошлом году велись махинации с включением/выключением складского учета. Это типичный источник возникновения «бабочек» (несогласованных остатков внутри аналитики счета).
Рассмотрим, как это происходит шаг за шагом:
С точки зрения общего сальдо по счету 10 (без детализации по складам) остаток равен нулю (1000 Дебет минус 1000 Кредит). Но для платформы это две совершенно разные записи в регистре. В зависимости от параметров виртуальной таблицы, наложения фильтров по субконто или наличия повреждений в итогах, эти записи могут некорректно схлопываться (сворачиваться) при построении запросов. Такое развернутое сальдо по закрытым аналитическим разрезам в среде разработчиков 1С называют «бабочкой».
Очень часто программисты сталкиваются с категорическим отказом бухгалтерии проводить пересчет итогов: «У нас закрыт прошлый год, сданы балансы, налоговая отчетность! Пересчет итогов все изменит, и нам придется сдавать уточненки!»
Выясним причину этого страха и полностью его опровергнем: это глубокое техническое заблуждение.
Пересчет итогов (будь то через Тестирование и Исправление, встроенные функции или программный код) выполняет только одну операцию: он полностью очищает вспомогательную таблицу итогов (кэш) и заново заполняет ее на основе реальных проводок, которые уже записаны в базе данных.
Здесь важно понимать два правила:
Рассмотрим практические методы исправления этой ошибки — от простых интерактивных до низкоуровневых административных решений.
Выделим наиболее эффективные варианты.
Если информационная база имеет огромный размер, то полный пересчет итогов через Конфигуратор («Тестирование и исправление») может затянуться на многие часы или даже сутки. К счастью, встроенный язык 1С позволяет выполнить точечный пересчет итогов конкретного регистра бухгалтерии за определенный интервал времени (например, за месяц или квартал, где возникла ошибка).
Для этого мы можем создать простую внешнюю обработку и выполнить следующий код:
// Определяем границы проблемного периода
ДатаНачалаПересчета = НачалоМесяца(Объект.ПроблемнаяДата);
ДатаОкончанияПересчета = КонецМесяца(Объект.ПроблемнаяДата);
// Вызываем метод менеджера регистра бухгалтерии для точечного пересчета
РегистрыБухгалтерии.Хозрасчетный.ПересчитатьИтогиЗаПериод(ДатаНачалаПересчета, ДатаОкончанияПересчета);
Сообщить("Пересчет итогов успешно выполнен для периода с " + ДатаНачалаПересчета + " по " + ДатаОкончанияПересчета);
Этот метод работает чрезвычайно быстро (обычно от нескольких секунд до нескольких минут), не требует монопольного режима работы пользователей и точечно перезаписывает кэш итогов только за указанный интервал. Данные за другие периоды остаются нетронутыми.
В платформе 1С:Предприятие 8.3 предусмотрен штатный инструмент управления итогами. Чтобы воспользоваться им, выполним следующие шаги:
РегистрБухгалтерии.Хозрасчетный (или нужный регистр накопления).На огромных базах данных (от 500 Гб и выше) даже штатное отключение и включение итогов средствами 1С может зависнуть из-за ограничений на размер транзакций СУБД или нехватки оперативной памяти. В этом случае администраторы баз данных прибегают к прямому вмешательству через SQL-запросы.
Проанализируем этот процесс:
Структура = ПолучитьСтруктуруХраненияБазыДанных();
// В полученной таблице ищем имя таблицы для регистра "Хозрасчетный" с постфиксом итоговости (обычно заканчивается на T1, T2 или Opt)
_AccRgT1), администратор СУБД выполняет команду очистки этой таблицы (например, в MS SQL Server Management Studio или pgAdmin):
TRUNCATE TABLE _AccRgT1;
ПересчитатьИтоги(). Платформа обнаруживает абсолютно пустую таблицу итогов и начинает быстро заполнять ее «с нуля» на основе существующих проводок, минуя фазу долгого удаления старых записей.Начиная с версии платформы 8.3.19, разработчики 1С внедрили новый механизм оптимизации индексов — хэширование измерений (DimHash). В редких случаях из-за багов платформы этот хэш рассчитывается некорректно, что приводит к задвоению записей в итогах и возникновению расхождений между таблицами остатков и оборотов.
Для исправления целостности хэша измерений обычный пересчет итогов из 1С может не помочь. В такой ситуации необходимо запустить утилиту командной строки 1cv8a, которая поставляется вместе с платформой 1С.
Синтаксис команды для исправления целостности выглядит так:
1cv8a.exe dbrepair --db-path "C:\PathToYourBase" --dimhash-integrity --repair
Для клиент-серверных баз вместо пути к файловой базе указываются параметры подключения к серверу 1С. Эта утилита на низком уровне пересчитает хэши всех измерений регистров, устранив логические ошибки платформы.
Если вы обнаружили предупреждение о расхождении остатков и оборотов, рекомендуем действовать по следующему плану:
Остатки и таблицы ОстаткиИОбороты за разные периоды (по дням). Найдите точный день, начиная с которого пошли расхождения.РегистрыБухгалтерии.Хозрасчетный.ПересчитатьИтогиЗаПериод() для локализованного временного интервала.