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

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет Торговля и дистрибуция
← На главную

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

В чем опасность длинных строк в измерениях регистра накопления?

Выясним технические причины, по которым строковое измерение приводит к сбоям системы:

  1. Превышение предельного размера ключа индекса в СУБД. В регистре накопления платформа автоматически строит составной кластерный индекс для таблицы итогов: Период плюс все измерения регистра. В Microsoft SQL Server лимит размера ключа индекса составляет 900 байт (в некоторых версиях — до 1700 байт), а в файловых базах .1CD — 1920 байт. Платформа 1С сохраняет строки в формате NVARCHAR, где на каждый символ выделяется 2 байта. Поле Строка(400) сразу забирает 800 байт. Добавив стандартные ссылки (номенклатура, контрагент, договор по 16 байт на UUID) и служебные поля, мы получаем гарантированную ошибку реструктуризации базы данных при обновлении.
  2. Разрастание таблицы итогов. Регистр накопления предназначен для агрегации данных. Если в измерение попадает уникальный текст, итоги перестают сворачиваться. Таблица итогов по количеству записей становится сопоставимой с таблицей движений, что кратно замедляет проведение документов и расчет срезов остатков.
  3. Проблема «зависания» остатков из-за форматирования. Любая разница в неразрывных пробелах, регистрах символов или переводах строк приводит к тому, что приход и расход не закрывают друг друга. Регистр не выходит в ноль, накапливая параллельные движения (+1 и -1), которые остаются в актуальных итогах навсегда.

Рассмотрим несколько правильных архитектурных вариантов решения этой задачи.

Вариант 1. Вынос текста в подчиненный регистратору регистр сведений

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

Разберем по шагам реализацию этого механизма:

  1. Из регистра накопления РеализованныеТоварыКомитентов удаляем строковое измерение. Регистр восстанавливает нормальную свертку остатков.
  2. Создаем непериодический регистр сведений СодержаниеУслугКомитентов с режимом записи Подчинение регистратору.
  3. В регистре сведений создаем измерение ИдентификаторСтроки (тип Число(10,0) или УникальныйИдентификатор) и ресурс Содержание (неограниченная строка).
  4. При проведении документа «Реализация товаров и услуг» формируем движения по регистру сведений параллельно с движениями регистра накопления.
  5. В документе «Отчет комитенту о продажах» остатки рассчитываются стандартным запросом к регистру накопления, а текст содержания извлекается через левое соединение по партии (ссылке на документ реализации) и номеру строки:

ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.КоличествоОстаток КАК Количество,
    ЕСТЬNULL(ДанныеСодержания.Содержание, "") КАК Содержание
ИЗ
    РегистрНакопления.РеализованныеТоварыКомитентов.Остатки(&Период, ) КАК Остатки
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СодержаниеУслугКомитентов КАК ДанныеСодержания
        ПО Остатки.Партия = ДанныеСодержания.Регистратор
        И Остатки.НомерСтрокиДокумента = ДанныеСодержания.ИдентификаторСтроки

Вариант 2. Связка через справочник описаний и расчет хеш-суммы

Если текст в содержании услуг периодически повторяется, его можно нормализовать с помощью отдельного справочника. В регистр накопления помещается ссылка на элемент этого справочника (размер поля в индексе составит всего 16 байт вместо сотен байт текста).

Чтобы избежать появления дублирующих записей в справочнике при сохранении неограниченных строк, применим механизм расчета хеш-суммы (например, MD5 или CRC32):

  1. Создаем справочник СодержанияУслуг. В реквизитах создаем Содержание (строка неограниченной длины) и индексируемый реквизит ХешСумма (строка 32 символа).
  2. Перед записью реализации программно получаем хеш введенной пользователем строки.
  3. Ищем существующий элемент в справочнике по хеш-сумме. Если он найден и исходные строки совпадают — используем найденную ссылку. Если нет — создаем новый элемент.
  4. В регистре накопления создаем измерение с типом СправочникСсылка.СодержанияУслуг.

Посмотрим на пример функции получения ссылки на содержание:


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

Вариант 3. Использование ключей аналитики учета

Это наиболее надежный архитектурный подход, используемый в современных типовых конфигурациях (таких как ERP, КА и БП 3.0 в учете НДС). Вместо набора текстовых полей создается пара: справочник КлючиАналитикиУчета и непериодический независимый регистр сведений АналитикаУчета.

Разберем логику работы механизма:

  1. Текст содержания разбивается на формализованные учетные разрезы (договор, дата, вид операции, проект).
  2. Регистр сведений хранит комбинацию этих разрезов в своих измерениях, а в ресурсе содержит ссылку на справочник ключей аналитики.
  3. В регистр накопления в качестве единственного дополнительного измерения передается ссылка на КлючАналитики.
  4. При проведении система сначала проверяет регистр сведений на наличие существующей комбинации аналитик. Если комбинация найдена, берется готовый ключ. Если комбинация новая, создается новый элемент справочника и новая запись в регистре сведений.

Этот метод гарантирует абсолютную компактность таблиц итогов регистра накопления и исключает появление дублей данных при повторных операциях.

Как выполнить миграцию существующих данных?

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

  1. Документом корректировки записей регистров списываем текущие остатки с регистра накопления, чтобы таблица итогов полностью обнулилась.
  2. Создаем новые метаданные (подчиненный регистр сведений или справочник).
  3. Удаляем строковое измерение из регистра накопления в конфигураторе и применяем изменения.
  4. Обработкой переносим данные из документов реализации в новую структуру и повторно формируем актуальные движения и остатки.
← На главную