← Назад к вопросам

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

1.3 Junior🔥 111 комментариев
#Регистры

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Регистр накопления типа "Обороты" часто становится узким местом при выборке больших объёмов данных. Вот проверенные методы ускорения.

1. Использование агрегатов

Это основной инструмент оптимизации:

// Регистр накопления: РегистрыНакоплений.СчетаАналитика (тип Обороты)
// На регистре созданы два агрегата:
// - СчетаАналитика_Дт (для дебета)
// - СчетаАналитика_Кт (для кредита)

// БЕЗ агрегата (медленно — полная выборка):
Запрос = Новый Запрос("SELECT * FROM РегистрыНакоплений.СчетаАналитика");
Результат = Запрос.Выполнить();
// Время: 5-10 сек на 1 млн записей

// С агрегатом (быстро — предвычисленные итоги):
Запрос = Новый Запрос(
    "SELECT * FROM РегистрыНакоплений.СчетаАналитика.Дт"
);
Результат = Запрос.Выполнить();
// Время: 100-500 мс на 1 млн записей

Как это работает:

Платформа автоматически создаёт две дополнительные таблицы:

  • РегистрыНакоплений_СчетаАналитика_Дт — дебетовые обороты (агрегирован)
  • РегистрыНакоплений_СчетаАналитика_Кт — кредитовые обороты (агрегирован)

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

2. Правильное кеширование измерений в агрегате

// При создании агрегата в конфигураторе:
// - Включить "Ускорение" (для дебета и кредита отдельно)
// - Выбрать ключевые измерения для группировки:
//   Счёт, Контрагент, Проект, Подразделение
//   (то, по чему часто группируют в отчётах)

Пример агрегата с правильным выбором измерений:

Процедура ФизическоеОсвещение()
    
    // Оптимально:
    // Измерения: Счёт, Контрагент
    // Ресурсы: Дебет, Кредит, Кол-во
    
    // Когда выполняется:
    Запрос = Новый Запрос(
        "SELECT Счёт, Контрагент, SUM(Дебет) as ОборотДебет 
         FROM РегистрыНакоплений.Счета.Дт 
         WHERE Период >= &НачалоПериода 
         GROUP BY Счёт, Контрагент"
    );
    
    // Платформа использует агрегат вместо полной выборки!
    
КонецПроцедуры

3. Индексы на базе данных

Добавить индексы на часто используемые поля:

-- SQL для админа БД
CREATE INDEX idx_счета_период 
    ON РегистрыНакоплений_СчетаАналитика_Дт(Счёт, Период);

CREATE INDEX idx_контрагент_период 
    ON РегистрыНакоплений_СчетаАналитика_Дт(Контрагент, Период);

CREATE INDEX idx_период 
    ON РегистрыНакоплений_СчетаАналитика_Дт(Период);

4. Фильтрация в запросе

Всегда фильтруй по периоду и другим полям в самом запросе:

// ПЛОХО (выбирает ВСЕ данные, потом фильтрует в памяти):
Запрос = Новый Запрос("SELECT * FROM РегистрыНакоплений.СчетаАналитика.Дт");
Результат = Запрос.Выполнить();
Для каждого Стр Из Результат.Выбрать() Цикл
    Если Стр.Период >= &НачалоПериода И Стр.Период <= &КонецПериода Тогда
        // обработать
    КонецЕсли;
КонецЦикла;

// ХОРОШО (фильтрует на БД):
Запрос = Новый Запрос(
    "SELECT Счёт, Контрагент, SUM(Дебет) as Дебет, SUM(Кредит) as Кредит 
     FROM РегистрыНакоплений.СчетаАналитика.Дт 
     WHERE Период >= &НачалоПериода 
       AND Период <= &КонецПериода 
       AND Счёт IN (&Перечень_Счетов) 
     GROUP BY Счёт, Контрагент"
);
Запрос.УстановитьПараметр("НачалоПериода", &НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", &КонецПериода);
Запрос.УстановитьПараметр("Перечень_Счетов", Перечень_Счетов);

Результат = Запрос.Выполнить();
// Результат: 100x ускорение!

5. Использование GROUP BY и SUM в запросе

// Вместо выборки всех записей и затем сведения в коде:

// БЫСТРО (прямой запрос с агрегацией):
Запрос = Новый Запрос(
    "SELECT 
        Счёт,
        Контрагент,
        Подразделение,
        SUM(Дебет) as ОборотДебет,
        SUM(Кредит) as ОборотКредит
    FROM РегистрыНакоплений.СчетаАналитика.Дт
    WHERE Период >= &ДатаНач AND Период <= &ДатаКон
    GROUP BY Счёт, Контрагент, Подразделение
    ORDER BY Счёт"
);
Запрос.УстановитьПараметр("ДатаНач", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКон", КонецМесяца(ТекущаяДата()));

Результат = Запрос.Выполнить();
// Результат: 1 млн записей обрабатывается в 50-100 мс

6. Кеширование результатов в памяти

// Если один и тот же запрос выполняется много раз:

Переменная КешОборотов = Новый Соответствие();

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

7. DISTINCT в запросе для удаления дублей

// Если нужны уникальные значения:

Запрос = Новый Запрос(
    "SELECT DISTINCT 
        Счёт,
        Контрагент
     FROM РегистрыНакоплений.СчетаАналитика.Дт
     WHERE Период >= &Дата"
);
// DISTINCT удаляет дубли на уровне БД быстрее, чем в коде

8. LEFT JOIN для связи с справочниками (избежать циклов)

// МЕДЛЕННО (цикл в коде — тысячи запросов):
Запрос = Новый Запрос("SELECT * FROM РегистрыНакоплений.СчетаАналитика.Дт");
Результат = Запрос.Выполнить();
Для каждого Стр Из Результат.Выбрать() Цикл
    СчетОбъект = Стр.Счёт.ПолучитьОбъект(); // запрос в цикле!
    // обработать
КонецЦикла;

// БЫСТРО (один запрос с JOIN):
Запрос = Новый Запрос(
    "SELECT 
        Дт.Счёт,
        Дт.Дебет,
        Счета.Наименование as НаименованиеСчета
     FROM РегистрыНакоплений.СчетаАналитика.Дт as Дт
     LEFT JOIN Справочник_Счета as Счета
         ON Дт.Счёт = Счета.Ссылка"
);
// Результат: 100x ускорение вместо цикла с запросами

9. Архивирование старых данных

Перемещение старых записей в архивный регистр:

// Если регистр содержит данные за 5 лет,
// а используются только последний год:

Процедура ПереместитьВАрхив()
    
    // Создать отдельный регистр РегистрыНакоплений.СчетаАналитика_Архив
    
    // Переместить старые данные
    Запрос = Новый Запрос(
        "SELECT * FROM РегистрыНакоплений.СчетаАналитика.Дт 
         WHERE Период < &ДатаГраница"
    );
    
    // Таблица становится меньше → агрегаты работают быстрее
    
КонецПроцедуры

Сравнение производительности

ПодходОбъём данныхВремяПримечание
Без оптимизации1 млн10+ секПолная выборка
С агрегатом1 млн50-200 мсПредвычисленные итоги
С индексом1 млн200-500 мсБыстрый поиск
С GROUP BY1 млн50-100 мсАгрегация на БД
С кешемN/A1 мсИз памяти

Чеклист оптимизации

  • Создан агрегат для регистра накопления оборотов
  • В агрегате выбраны правильные измерения (по которым группируют)
  • В запросах всегда фильтруется по периоду
  • Используется GROUP BY/SUM в запросе, а не в коде
  • Добавлены индексы на часто используемые поля
  • Кеширование результатов для часто запрашиваемых данных
  • Старые данные архивированы
  • Протестирована производительность с реальным объёмом

Итого: агрегаты + правильные запросы = 100x ускорение выборки из регистра накоплений оборотов.

Что можно сделать с регистром накопления оборотов, чтобы ускорить процесс получения данных из него? | PrepBro