Регистры накопления 1С 8.2

Регистр накопления – объект конфигурации, предназначенный для хранения итоговых (накопленных) значений показателей и хранения движений (приращений) показателей.

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

Итоги оборотных показателей отображают значения совокупного изменения показателя за временной интервал между двумя моментами времени(период).

Итоги показателей остатков отражают значения учитываемых показателей на некоторый момент времени.

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

Итоги оборотных показателей за разные периоды независимы.

Данные каждого регистра накопления хранятся в базе данных в двух
таблицах:
  • таблица движений регистра накопления,
  • таблица итогов регистра накопления.

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

Для таблиц движений регистров создаются следующие индексы:
  • Период + Регистратор + НомерСтроки;
  • Регистратор + НомерСтроки;
  • Измерение + Период + Регистратор + НомерСтроки, если для измерения Измерение свойство Индексировать установлено в значение Индексировать;
  • Реквизит + Период + Регистратор + НомерСтроки, если для реквизита Реквизит свойство Индексировать установлено в значение Индексировать.
Для таблиц итогов создается следующий индекс:
  • Период + Измерение1 + Измерение2 + … + ИзмерениеN + Разделитель – по всем измерениям регистра;
  • Измерение + Период, если для измерения Измерение свойство Индексировать установлено в значение Индексировать.
Microsoft SQL Server накладывает определенное ограничение на количество полей, входящих в составной индекс, – не более 16 полей в индексе. Поэтому работа с регистрами, имеющими очень большое количество измерений, может быть неэффективна по скорости из-за невозможности использования индексных таблиц.

Взаимосвязь таблиц движений и итогов

При формировании данных таблицы итогов важно обеспечить их непротиворечивость данным таблицы движений.

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

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

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

ПризнакИспользованияИтогов = РегистрыНакопления.ПартииТоваров.ПолучитьИспользованиеИтогов();
Если ПризнакИспользованияИтогов Тогда
   Сообщение = Новый СообщениеПользователю();
   Сообщение.Текст = "Итоги по регистру 'ПартииТоваров' рассчитываются";
   Сообщение.Сообщить();
КонецЕсли;

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


// Включить использование итогов регистра 
// (одновременно выполнится пересчет итогов).
РегистрыНакопления.ПартииТоваров.УстановитьИспользованиеИтогов(Истина);

При включении использования итогов система производит пересчет всех итогов с момента самого раннего движения, сделанного после отключения активности итогов.

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


Запись данных в таблицу движений регистра накопления

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

Регистры накопления не поддерживают независимого формирования записей без использования документа-регистратора. Этим достигается обоснованность информации регистров – данными документов.

Для заполнения или модификации данных таблицы движений есть две возможности:
  • посредством создания набора записей регистра с обязательным отбором по регистратору;
  • посредством использования свойства объекта документа Движения, представляющего собой коллекцию наборов записей, подчиненных данному регистратору.
Важно понимать, что платформа во многих механизмах использует обращение к элементам коллекции Движения. Например, при удалении документа система будет для каждого регистра, в котором он может быть регистратором, проверять наличие движений документа с целью их удаления. Поэтому не рекомендуется включать в коллекцию Движения элементы «с запасом». И наоборот, если указано, что документ не может быть регистратором для некоего регистра, то система никоим образом не позволит записать в данный регистр движения данного документа.

Формирование движений при проведении документа

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

  • С точки зрения платформы отдельного процесса «проведение» не существует. Есть запись документа с проведением, причем в рамках одной транзакции. Таким образом, в момент выполнения обработчика события ОбработкаПроведения документ уже записан. То есть разработчику не нужно беспокоиться о предотвращении попыток проведения незаписанных документов.
  • Свойство Удаление движений документа как объекта конфигурации стандартно устанавливается платформой в значение Удалять автоматически при отмене проведения. Это значит, что при перепроведении документа движения, подчиненные данному документу, перезаписываются, а при отмене проведения движения документа автоматически удаляются. Если разработчик захочет реализовать нестандартный вариант проведения документа и установит свойство Удаление движений в значение Удалять автоматически, то при записи документа  с проведением сначала будут удалены все старые движения документа.
    То есть на момент выполнения обработчика события ОбработкаПроведения в регистрах не будет наборов записей с движениями данного документа.
  • При записи с проведением система автоматически запишет выбранные и незаписанные наборы записей, находящиеся в свойстве Движения. Это еще один «сервис», обеспечиваемый свойством Движения. 
Отсюда следуют два важных вывода:
  1. Если наборы записей необходимо записывать с добавлением, то это нужно выполнять в явном виде, т. к. при автоматической записи движений они будут записаны с замещением.
  2. Последовательность обращения к регистрам при автоматической записи движений будет одна и та же для разных документов. Это позволяет снизить вероятность взаимных блокировок при проведении документа в конкурентных режимах работы.

Формирование движений в объекте документа, но без проведения документа

Кроме выполнения самих движений при формировании движений вне процедуры, обрабатывающей проведение документа, необходимо:
  • контролировать, чтобы документ был сохранен на момент записи движений в регистр (записи должны содержать ссылку на регистратор);
  • решать, что делать со старыми движениями документа;
  • явно записывать сформированные наборы записей движений.

Активность движений

Снятие активности движений – по сути дела та же задача модификации движений документа, только в отношении поля Активность, и может выполняться аналогично. Однако с прикладной точки зрения свойство записи движения Активность особое.

Во-первых, наличие активных движений документа в регистре означает, что данный документ отражен в неком аспекте учета. Вернее, в учете отражено событие, зафиксированное данным документом.

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

В-третьих, наличие движений документа в регистре, из которых часть активна, а часть неактивна, с точки зрения практического применения нонсенс. Например, попробуйте представить себе ситуацию: «Отгружено пять пылесосов и холодильник, но не совсем. Холодильник не отгружен». Поэтому платформа не допускает записи набора записей
движений регистра, если часть записей в этом наборе активна, а часть – нет.

В системе предусмотрена возможность установки и снятия активности целиком для всего набора записей посредством метода УстановитьАктивность() набора записей регистра накопления.

Пример формирования движений документов

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

   НаборЗаписейРегистра.Отбор.Регистратор.Установить(ВыборкаДокументов.Ссылка);
  
   // Перебрать данные о составе документа, необходимые для заполнения формируемых движений. 

   ВыборкаДетальныхЗаписей = ВыборкаДокументов.Выбрать();
   Пока ВыборкаДетальныхЗаписей.Следующий() Цикл
   
    // Сформировать движения по регистру Продажи. 
    НоваяЗапись = НаборЗаписейРегистра.Добавить();
    НоваяЗапись.Период = ВыборкаДетальныхЗаписей.Дата;
    НоваяЗапись.Номенклатура = ВыборкаДетальныхЗаписей.Номенклатура;
    НоваяЗапись.Количество = ВыборкаДетальныхЗаписей.Количество;
    НоваяЗапись.Сумма = ВыборкаДетальныхЗаписей.Сумма;
    НоваяЗапись.Контрагент = ВыборкаДокументов.Контрагент;
    НоваяЗапись.ВидОперации = ВыборкаДокументов.ВидОперации;
   КонецЦикла;
  
   // Записать сформированные для очередного документа движения.
   НаборЗаписейРегистра.Записать();
  
   // Очистить набор записей регистра 
   // перед использованием для следующего документа.
   НаборЗаписейРегистра.Очистить();
  
  КонецЦикла;
 
КонецПроцедуры 


Механизм заполнения таблицы итогов регистра накопления остатков

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

Текущие (актуальные) итоги – это итоговые значения учитываемых в регистре ресурсов (показателей) на момент времени заведомо больший, нежели любое значение поля Период записей таблицы движений. Для определенности текущие итоги регистров остатков датированы на 01.11.3999 00:00:00.

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

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


Расчет итогов может быть выполнен программно:

РегистрыНакопления.ТоварыНаСкладах.УстановитьПериодРассчитанныхИтогов(Дата(2010, 05, 31));

Наличие посчитанных по конец каждого месяца итогов положительно сказывается на быстродействии обращений к остаткам регистра. Расчет остатков начинается с определения ближайшего равного или большего итога (хранимого в таблице итогов регистра)  с последующим «досчетом» остатка на нужный момент времени по таблице движений.

Но зачастую может сложиться ситуация, что граница рассчитанных итогов очень сильно «отстает» от периода самой последней записи в регистре. Данное положение не сказывается на функциональности регистра, сказывается только на быстродействии обращений к его остаткам. Поскольку досчет тогда будет производиться, скорее всего, по большому количеству
записей.

Механизм заполнения таблицы итогов оборотного регистра накопления

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

Обратите внимание: поле Период заполняется значением даты начала периода (месяца), по которому хранятся итоги.

Режим разделения итогов

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

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

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

Механизм разделения итогов вводит в состав хранимой таблицы итогов специальное поле (Разделитель), позволяющее распараллелить обновление записей итогов.

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

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

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

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

Чтобы управлять работой данного механизма, предусмотрены две возможности.

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

Признак использования разделения итогов для регистров (для которых разделение итогов разрешено в конфигурации) может быть получен и установлен программно методами менеджера регистра накопления ПолучитьРежимРазделенияИтогов() и УстановитьРежимРазделенияИтогов(), а также в стандартной функции управления итогами (Все функции -> Стандартные -> Управление итогами -> Полные возможности -> Разделение итогов -> Включить разделение итогов/Выключить разделение итогов).

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

 Получение данных из регистров накопления

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

Вопросы быстродействия системы при получении движений

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

Если требуется получить записи, исключая граничные, необходимо использовать объект Граница. Пример получения выборки в интервале дат, исключая границы интервала:

ГраницаНачалаИнтервала = Новый Граница(НачалоИнтервала,ВидГраницы.Исключая);
ГраницаКонцаИнтервала = Новый Граница(КонецИнтервала, ВидГраницы.Исключая);
ВыборкаДвижений = РегистрыНакопления.ТоварыНаСкладах.Выбрать(ГраницаНачалаИнтервала,
            ГраницаКонцаИнтервала);
Пока ВыборкаДвижений.Следующий() Цикл
  // Выполнить действие с очередным движением.
  // ...
  
КонецЦикла;


8 комментариев: