Как объединить данные по разным видам оплат и оптимизировать получение оборотов в 1С

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

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

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

Анализ проблемы: почему запросы к документам — это ошибка

Рассмотрим ситуацию: в системе есть два типа документов или два вида операций (наличные и эквайринг). Автор задачи хочет объединить их в один поток данных, убрав разрез по виду оплаты, и при этом сделать это максимально незаметно для пользователя. Первое импульсивное решение, которое часто приходит в голову — написать запрос с использованием оператора ОБЪЕДИНИТЬ ВСЕ (UNION ALL) к таблицам документов.

Проанализируем, к чему это приведет при росте базы:

  1. Full Table Scan: СУБД (SQL Server, PostgreSQL и др.) будет вынуждена сканировать физические таблицы документов целиком, так как у документов нет оптимизированных таблиц итогов для расчета оборотов.
  2. Избыточность данных: Документы содержат много лишней информации (комментарии, служебные реквизиты), которая не нужна для отчетов, но нагружает дисковую подсистему при чтении.
  3. Блокировки: При попытке построить отчет «на лету» по таблицам документов, система может накладывать блокировки, мешая оперативной работе пользователей.

Посмотрим на рекомендации опытных разработчиков: единственный верный способ решения задачи — внедрение Регистра накопления.

Шаг 1: Создание регистра накопления для консолидации данных

Вместо того чтобы пытаться создать «консолидирующий документ», который будет дублировать данные, мы создадим объект РегистрНакопления с видом «Обороты». Это позволит нам хранить данные в свернутом и оптимизированном виде.

Разберем структуру будущего регистра:

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

Шаг 2: Реализация механизма записи через подписки на события

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

Проанализируем пример кода, который может быть размещен в модуле подписки:


Процедура ПриПроведенииПродажи(Источник, Отказ, РежимПроведения) Экспорт
    
    // Подготавливаем набор записей нашего нового регистра
    НаборЗаписей = РегистрыНакопления.ПродажиКонсолидированные.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Регистратор.Установить(Источник.Ссылка);
    
    // Заполняем движения на основании данных документа
    Для Каждого СтрокаТЧ Из Источник.Товары Цикл
        Движение = НаборЗаписей.Добавить();
        Движение.Период = Источник.Дата;
        Движение.Регистратор = Источник.Ссылка;
        Движение.Номенклатура = СтрокаТЧ.Номенклатура;
        Движение.Количество = СтрокаТЧ.Количество;
        Движение.Сумма = СтрокаТЧ.Сумма;
    КонецЦикла;
    
    // Записываем движения
    НаборЗаписей.Записать();
    
КонецПроцедуры

Использование свойства ОбменДанными.Загрузка = Истина при программной записи может потребоваться только в специфических случаях, но в стандартном процессе проведения мы просто формируем движения по новому регистру. Это гарантирует, что при отмене проведения документа данные из консолидированного регистра также «уйдут» автоматически.

Шаг 3: Обработка исторических данных (задним числом)

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

Разберем алгоритм безопасного заполнения:

  1. Создаем обработку для фонового заполнения данных.
  2. Выбираем документы порциями (например, по 500-1000 штук) в транзакции.
  3. Для каждого документа вызываем только механизм записи движений в новый регистр, без полного перепроведения.

Посмотрим, как эффективно работать с набором записей без лишних проверок:


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

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

Почему «Консолидирующий документ» — это плохое решение

Автор темы изначально рассматривал вариант создания некоего общего документа. Выясним, почему коллеги на форуме категорически против этого:

Регистр накопления лишен этих недостатков. Он является подчиненным объектом (движением) по отношению к документу-регистратору. Платформа 1С берет на себя всю работу по контролю целостности: если документ удаляется, его движения по регистру стираются автоматически.

Итоги и рекомендации

Подведем итог нашему анализу. Чтобы объединить продажи по разным видам оплат и обеспечить быструю работу системы при росте базы, следует придерживаться следующего плана:

  1. Откажитесь от UNION запросов к документам в отчетах. Это путь к деградации производительности.
  2. Внедрите оборотный регистр накопления. Это «золотой стандарт» архитектуры 1С для хранения итогов.
  3. Используйте подписки на события, чтобы сделать процесс записи данных в регистр прозрачным для кода существующих документов и для пользователей.
  4. Заполняйте исторические данные порционно в периоды низкой нагрузки на базу.

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

← На главную