Почему зависают остатки в регистре накопления 1С и как это исправить?

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

При разработке и сопровождении конфигураций на платформе «1С:Предприятие 8» разработчики часто сталкиваются с крайне неприятной проблемой: в отчетах начинают отображаться некорректные остатки. Вроде бы товар или ресурс был полностью списан, но при детальной настройке отчета с выводом всех группировок обнаруживаются странные «зависшие» или «встречные» остатки — положительные по одной аналитике и отрицательные по другой. В нашей статье мы подробно разберем, почему возникает такая ситуация, как она влияет на базу данных и какими способами можно навсегда решить эту проблему.

Проанализируем ситуацию: суть проблемы неполного заполнения измерений

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

При поступлении ТМЦ (документ прихода) проведение выполняется корректно по всем трем измерениям. Например, на склад «Основной» поступает товар от контрагента «Поставщик», а ответственным лицом (измерение Сотрудник) записывается «Иванов». Ресурс Количество увеличивается на 10 единиц.

При списании ТМЦ (документ расхода) разработчик по какой-то причине решает заполнить только измерения Склад («Основной») и Контрагент («Поставщик»), оставляя измерение Сотрудник пустым. Программа без проблем проводит документ, уменьшая количество на 10 единиц. Но что происходит, когда мы пытаемся получить остатки в отчете с выводом всех трех измерений? Мы видим давно списанные данные: по сотруднику «Иванов» висит остаток +10, а по пустому сотруднику — остаток -10.

Выясним причину на уровне базы данных (СУБД)

Чтобы понять, почему остатки зависают, заглянем на физический уровень работы СУБД (например, MS SQL Server или PostgreSQL). Для регистра накопления остатков платформа 1С создает в базе данных две ключевые таблицы:

  1. Таблица движений (хранит детальные записи всех приходов и расходов с привязкой к регистратору).
  2. Таблица итогов (хранит рассчитанные остатки на начало каждого месяца в разрезе уникальных комбинаций измерений).

Для оптимизации расчета итогов СУБД группирует записи строго по уникальным наборам значений измерений. В MS SQL Server для этого часто рассчитывается специальный хэш комбинации измерений — DimHash. Если при приходе были заполнены измерения Склад, Контрагент и Сотрудник, СУБД создает строку итогов с уникальным идентификатором этой тройки. Когда же при расходе поле Сотрудник остается пустым, СУБД воспринимает эту запись как совершенно другую комбинацию измерений.

В итоге в таблице итогов физически будут находиться две строки:

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

Чем опасны «зависающие» остатки для производительности

Наличие таких незакрытых встречных записей («плюс» по одному набору измерений и «минус» по другому) — это не просто визуальный дефект в отчете. Это серьезная техническая проблема, которая влечет за собой целый ряд негативных последствий:

Нюансы использования «пустых» значений в измерениях

Иногда разработчики намеренно оставляют измерения пустыми, предполагая, что система поймет это одинаково. Однако здесь есть неочевидные подводные камни:

Рассмотрим по шагам архитектурные варианты решения

Чтобы исправить данную проблему раз и навсегда, необходимо определиться с бизнес-логикой вашей задачи. Нужны ли вам остатки в разрезе сотрудников?

Вариант 1. Остатки по сотрудникам НЕ нужны

Если вам не требуется контролировать остатки по сотрудникам, а поле нужно исключительно для справочной информации (например, чтобы знать, какой сотрудник провел операцию), то хранить его в качестве измерения регистра остатков — это грубая архитектурная ошибка. По стандартам разработки фирмы «1С» измерения регистра остатков должны содержать только те разрезы, по которым действительно ведется учет остатков и которые гарантированно закрываются в ноль.

В такой ситуации правильным решением будет:

  1. Перенести сотрудника из Измерений в Реквизиты регистра накопления. Реквизиты не участвуют в формировании ключа уникальности в таблице итогов и не влияют на расчет остатков.
  2. Если вам все же нужна аналитика по оборотам сотрудников, то правильнее использовать отдельный Регистр оборотов, где Сотрудник будет полноценным измерением. Регистры оборотов не хранят остатки и не раздувают таблицы итогов встречными записями.

Вариант 2. Остатки по сотрудникам действительно НУЖНЫ

Если бизнес-логика требует жесткого контроля за тем, за каким именно сотрудником числятся ТМЦ, вы обязаны обеспечить симметричное закрытие регистра. Это означает, что при расходе вы должны указывать того же самого сотрудника, который был указан при приходе.

Для этого необходимо доработать модуль проведения расходного документа. Алгоритм проведения должен предварительно получать остатки из регистра по всем измерениям (включая сотрудника), а затем списывать их по определенной логике (например, по методу ФИФО, ЛИФО или по прямому выбору сотрудника в табличной части документа).

Как исправить существующие некорректные записи

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

Способ А. Групповое перепроведение документов

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

Способ Б. Программная корректировка движений (Набор записей)

Если период уже закрыт для редактирования (например, сдан бухгалтерский баланс) или документов слишком много и перепроведение займет слишком много времени, можно воспользоваться программным исправлением записей регистра через объект РегистрНакопленияНаборЗаписей.

Для этого пишется внешняя обработка, которая находит документы с незаполненными измерениями, программно открывает их набор записей регистра, заполняет недостающие измерения (или очищает их везде для симметрии) и перезаписывает набор без перепроведения самих документов. Рассмотрим пример кода:


// Пример программного исправления некорректных записей регистра
Процедура ИсправитьПустыеИзмерения() Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |   ТоварыНаСкладах.Регистратор КАК Регистратор
        |ИЗ
        |   РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
        |ГДЕ
        |   ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход)
        |   И ТоварыНаСкладах.Сотрудник = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)";
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        // Создаем набор записей для конкретного документа-регистратора
        НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);
        НаборЗаписей.Прочитать();
        
        Модифицирован = Ложь;
        Для Каждого Запись Из НаборЗаписей Цикл
            Если Запись.ВидДвижения = ВидДвиженияНакопления.Расход И Не ЗначениеЗаполнено(Запись.Сотрудник) Тогда
                // Определяем сотрудника по логике прихода (например, первый доступный остаток)
                Запись.Сотрудник = НайтиСотрудникаДляЗаполнения(Запись.Склад, Запись.Контрагент);
                Модифицирован = Истина;
            КонецЕсли;
        КонецЦикла;
        
        Если Модифицирован Тогда
            // Записываем набор записей с флагом замещения
            НаборЗаписей.Записать(Истина);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Способ В. Использование документов «Корректировка регистров»

Это крайний метод. Ввод ручных корректировок позволяет сопоставить и «схлопнуть» остатки в ноль (сделать расход по сотруднику и приход без сотрудника на ту же сумму). Однако это лишь маскирует проблему в кодовой базе и часто приводит к путанице у бухгалтеров и аналитиков. Используйте этот способ только тогда, когда программное исправление движений невозможно.

Обязательные действия после исправления данных

После того как записи в регистре были скорректированы (через перепроведение или обработку наборов записей), таблицы итогов в СУБД могут по-прежнему содержать старые «фантомные» записи или некорректно рассчитанные итоги. Чтобы физически очистить базу данных и восстановить её производительность, необходимо выполнить следующие регламентные операции:

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

Только после выполнения пересчета итогов вы заметите реальный прирост скорости работы отчетов и проведение документов без задержек.

← На главную