Найти в Дзене

Оптимизация работы с регистрами бухгалтерии, накопления

Знакомая картина: пользователь открывает отчёт «Оборотно-сальдовая ведомость» за год, нажимает «Сформировать» — и идёт пить кофе. Потом возвращается, видит, что отчёт всё ещё крутится, идёт пить второй кофе. Это не норма, это симптом. Регистры бухгалтерии и накопления — это сердце любой 1С-конфигурации, и когда это сердце начинает «барахлить», вся система замедляется до черепашьей скорости. Я работаю с 1С уже больше двенадцати лет, и за это время насмотрелся всякого: базы по 400 гигабайт, где простой запрос к регистру накопления выполняется 40 секунд, торговые компании с 15 миллионами записей в регистре остатков, у которых закрытие месяца занимало 8 часов. И в большинстве случаев проблема решалась — иногда элегантно, иногда грубой силой, но решалась. В этой статье разберём конкретные приёмы оптимизации, которые реально работают в боевых условиях. Прежде чем лечить, нужно понять, что болит. Регистры бухгалтерии и накопления — это не просто таблицы в базе данных, это целая экосистема со
Оглавление
Оптимизация работы 1С
Оптимизация работы 1С

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

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

Я работаю с 1С уже больше двенадцати лет, и за это время насмотрелся всякого: базы по 400 гигабайт, где простой запрос к регистру накопления выполняется 40 секунд, торговые компании с 15 миллионами записей в регистре остатков, у которых закрытие месяца занимало 8 часов. И в большинстве случаев проблема решалась — иногда элегантно, иногда грубой силой, но решалась. В этой статье разберём конкретные приёмы оптимизации, которые реально работают в боевых условиях.

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

Прежде чем лечить, нужно понять, что болит. Регистры бухгалтерии и накопления — это не просто таблицы в базе данных, это целая экосистема со своими итогами, индексами, агрегатами и механизмами пересчёта. Когда что-то идёт не так, причины обычно попадают в одну из нескольких категорий.

Раздутые таблицы движений

Самая частая история — таблица движений регистра разрослась до неприличных размеров. Видел базу торговой компании, где в регистре накопления «Товары на складах» было 47 миллионов записей. Причина простая: разработчики в своё время не настроили агрегаты и не думали об архивировании. Каждая продажа, каждое перемещение, каждая инвентаризация — всё копилось годами.

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

Проблемы с итогами

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

Бывает и обратная ситуация: итоги есть, но их слишком много. Например, когда период хранения итогов настроен неправильно и система хранит детальные итоги за 10 лет, хотя реально нужны данные только за 3 года. Лишние итоги — это лишний объём и лишнее время на обновление.

Отсутствие или неправильные агрегаты

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

Диагностика: как понять, что именно тормозит

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

Технологический журнал как главный инструмент

Первым делом включаем технологический журнал и смотрим, какие запросы выполняются долго. Настройка простая — в файле logcfg.xml указываем интересующие нас события и порог длительности. Обычно я ставлю порог в 3000 миллисекунд (3 секунды) — всё, что дольше, попадает в лог.

Ищем в логе события DBMSSQL или DBPOSTGRS — это обращения к базе данных. Смотрим на поле «Sql» — там будет текст запроса, и поле «Duration» — длительность в миллисекундах. Запросы к регистрам легко узнать по характерным именам таблиц: они содержат «_AccRg» (регистр бухгалтерии) или «_AccumRg» (регистр накопления).

Консоль запросов и план выполнения

Когда нашли проблемный запрос, берём его в консоль запросов и смотрим план выполнения. Если видите операцию «Table Scan» (полное сканирование таблицы) вместо «Index Seek» — это красный флаг. Значит, индексы не используются, и запрос перебирает миллионы записей по одной.

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

ВЫБРАТЬ
ОстаткиТоваров.Номенклатура,
ОстаткиТоваров.Склад,
ОстаткиТоваров.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
&ДатаОтчета,
Номенклатура В (&СписокНоменклатуры)
) КАК ОстаткиТоваров
ГДЕ
ОстаткиТоваров.КоличествоОстаток > 0

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

Мониторинг размеров таблиц

Полезно периодически смотреть на размеры таблиц в базе данных. Для SQL Server это делается через системные представления. Но проще воспользоваться обработкой из стандартной поставки или написать небольшой запрос прямо в 1С через внешнее соединение с информационной базой.

Ориентиры такие: таблица движений регистра накопления свыше 5 ГБ — повод задуматься; свыше 20 ГБ — уже серьёзная проблема, требующая немедленных действий. Для регистра бухгалтерии цифры примерно те же.

Оптимизация запросов к регистрам: конкретные приёмы

Начнём с самого доступного — оптимизации кода запросов. Это не требует изменения структуры базы и доступно даже в типовых конфигурациях через расширения.

Правильное использование виртуальных таблиц

Виртуальные таблицы — это главный инструмент работы с регистрами. Для регистра накопления это «Остатки», «Обороты», «ОстаткиИОбороты». Для регистра бухгалтерии — «Остатки», «Обороты», «ДвиженияССубконто» и другие.

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

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

И правильный вариант:

// ПРАВИЛЬНО - отбор в параметрах виртуальной таблицы
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
&Дата,
Склад = &НужныйСклад
) КАК Остатки

В первом случае система сначала получит остатки по всем складам, а потом отфильтрует. Во втором — сразу запросит только нужный склад. На больших базах разница может быть в 10-50 раз по скорости. Не преувеличение — реальные замеры с реальных проектов.

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

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

Пакетные запросы вместо цикличных обращений

Ещё одна классика жанра — обращение к регистру в цикле. Вижу такой код регулярно:

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

Если в таблице 500 товаров — это 500 запросов к базе. Правильное решение — передать весь список в один запрос:

// ХОРОШО - один запрос для всего списка
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Остатки.Номенклатура,
| Остатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| Номенклатура В (&СписокНоменклатуры)
| ) КАК Остатки";
Запрос.УстановитьПараметр("СписокНоменклатуры", СписокНоменклатуры);
РезультатЗапроса = Запрос.Выполнить();

Один запрос вместо пятисот. Экономия времени — от 90% до 99%, в зависимости от размера базы и нагрузки на сервер.

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

Агрегаты — это предвычисленные итоги, которые хранятся отдельно и позволяют системе отвечать на запросы об остатках практически мгновенно. Правильно настроенные агрегаты могут ускорить запросы к регистру накопления в 100 и более раз. Без шуток.

Как работают агрегаты

Представьте, что у вас регистр накопления «Товары на складах» с измерениями: Номенклатура, Склад, Характеристика. Агрегат — это предвычисленный итог по какому-то подмножеству измерений. Например, агрегат «Номенклатура + Склад» хранит суммарные остатки по каждой комбинации номенклатуры и склада без учёта характеристики.

Когда приходит запрос «покажи мне остатки по складу №3», система смотрит, есть ли подходящий агрегат. Если есть — берёт данные оттуда, не трогая миллионы строк в таблице движений. Если нет — идёт в таблицу движений и перебирает всё подряд.

Настройка агрегатов в конфигураторе

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

Практические рекомендации по настройке агрегатов:

  • Добавляйте агрегаты для тех комбинаций измерений, которые реально используются в отчётах и запросах
  • Не добавляйте агрегат с полным набором всех измерений — это бессмысленно, это просто дублирование итогов
  • Оптимальное количество агрегатов — 3-7 штук на регистр
  • После добавления агрегатов обязательно выполните их пересчёт
  • Используйте режим «оптимальные агрегаты» — 1С сама предложит варианты на основе анализа запросов

Механизм оптимальных агрегатов — это вообще отдельная песня. Система анализирует реальные запросы к регистру и предлагает набор агрегатов, который покроет максимальное количество запросов с минимальными затратами на хранение. Очень полезная штука, особенно когда не знаешь, с чего начать.

Обновление агрегатов в фоне

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

Оптимизация структуры регистров и итогов

Иногда проблема не в запросах и не в агрегатах, а в самой структуре регистра. Это сложнее поправить в типовой конфигурации, но в самописных или сильно доработанных — вполне реально.

Период хранения итогов

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

Если пользователи постоянно смотрят отчёты за прошлые периоды, имеет смысл сдвинуть границу назад. Но тогда вырастет объём таблицы итогов. Нужно найти баланс.

Управлять границей итогов можно программно:
// Установка границы актуальности итогов регистра накопления
РегистрНакопления.ТоварыНаСкладах.УстановитьГраницуАктуальностиИтогов(
НачалоГода(ТекущаяДата())
);

Или через обработку «Управление итогами» в режиме предприятия. Рекомендую делать пересчёт итогов ежемесячно в рамках регламентных операций — это профилактика, которая стоит 15 минут времени и экономит часы работы пользователей.

Разделение регистров по периодам

Радикальный, но эффективный приём для очень больших баз — разделить данные на «горячие» (актуальные) и «холодные» (архивные). Создаётся отдельный регистр-архив, куда переносятся данные старше, например, трёх лет. Основной регистр остаётся компактным и быстрым.

Это требует серьёзной доработки отчётности — нужно научить отчёты смотреть в архив при необходимости. Но для компаний с историей данных 10+ лет и активной торговлей это иногда единственный выход без покупки нового железа.

Лишние измерения в регистрах

Ещё одна причина тормозов — избыточные измерения в регистре. Каждое измерение увеличивает количество комбинаций в таблице итогов. Если в регистре есть измерение, которое фактически не используется в запросах — это балласт.

Например, видел регистр накопления, в котором было измерение «МенеджерПродажи». Оно добавлялось «на всякий случай» три года назад, но ни один отчёт его не использовал. При этом у компании 20 менеджеров — значит, таблица итогов была в 20 раз больше необходимого. Убрали измерение — таблица итогов похудела в 18 раз (с учётом того, что некоторые менеджеры вели схожие позиции).

Практический кейс: оптимизация закрытия месяца

Расскажу про реальный проект. Производственная компания, 1С:Комплексная автоматизация (стоимость лицензий на тот момент — около 54 000₽ за основную поставку плюс клиентские лицензии). 45 пользователей, база 280 ГБ, работает 7 лет.

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

Что нашли при диагностике

  • Таблица движений регистра бухгалтерии — 38 миллионов записей, 22 ГБ
  • Таблица движений основного регистра накопления — 67 миллионов записей, 41 ГБ
  • Агрегаты не использовались вообще — галочка была снята
  • Итоги не пересчитывались с момента внедрения (7 лет!)
  • Несколько запросов в процедурах закрытия работали по принципу «запрос в цикле»
  • Индексы на таблицах движений были фрагментированы на 70-80%

Что сделали и что получили

Работы заняли две недели. Последовательность действий:

  • Перестроили индексы базы данных — это заняло 6 часов, но сразу дало 20% прирост производительности
  • Пересчитали итоги регистров — ещё 4 часа, но зато теперь они актуальны
  • Включили агрегаты для основного регистра накопления, добавили 4 агрегата по наиболее частым комбинациям измерений
  • Переписали три процедуры в закрытии месяца, убрав запросы из циклов
  • Настроили еженедельное регламентное задание для перестройки индексов

Результат: закрытие месяца сократилось с 11 часов до 2 часов 20 минут. Бухгалтеры счастливы. Директор счастлив. Мы тоже довольны. Стоимость работ по оптимизации составила около 180 000₽ — это окупилось за первые три месяца только за счёт сэкономленного рабочего времени сотрудников.

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

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

Ежедневные задания

  • Обновление агрегатов регистров накопления (если используется отложенное обновление)
  • Резервное копирование базы данных
  • Обновление статистики таблиц базы данных (для SQL Server)

Еженедельные задания

  • Перестройка фрагментированных индексов (фрагментация свыше 30%)
  • Реорганизация слабо фрагментированных индексов (фрагментация 10-30%)
  • Проверка целостности базы данных (DBCC CHECKDB для SQL Server)

Ежемесячные задания

  • Пересчёт итогов регистров накопления
  • Пересчёт итогов регистров бухгалтерии
  • Анализ размеров таблиц и динамики роста
  • Проверка актуальности агрегатов (возможно, нужно добавить новые или убрать неиспользуемые)

Для автоматизации обслуживания SQL Server удобно использовать планы обслуживания или скрипты Ola Hallengren — это бесплатный набор скриптов для обслуживания SQL Server, который стал фактическим стандартом в 1С-сообществе. Настроить его один раз — и забыть про фрагментацию индексов навсегда.

Пример регламентной процедуры пересчёта итогов

// Регламентная процедура пересчёта итогов
Процедура ПересчитатьИтогиРегистров() Экспорт

// Пересчёт итогов регистра накопления
Попытка
РегистрНакопления.ТоварыНаСкладах.ПересчитатьИтоги();
РегистрНакопления.ВзаиморасчётыСКонтрагентами.ПересчитатьИтоги();
Исключение
ЗаписатьОшибкуВЖурнал(
"Ошибка пересчёта итогов регистров накопления: " +
ОписаниеОшибки()
);
КонецПопытки;

// Пересчёт итогов регистра бухгалтерии
Попытка
РегистрБухгалтерии.Хозрасчётный.ПересчитатьИтоги();
Исключение
ЗаписатьОшибкуВЖурнал(
"Ошибка пересчёта итогов регистра бухгалтерии: " +
ОписаниеОшибки()
);
КонецПопытки;

КонецПроцедуры

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

Частые ошибки разработчиков при работе с регистрами

Напоследок — краткий хит-парад ошибок, которые я встречаю чаще всего. Если вы узнаёте свой код — не расстраивайтесь, мы все через это прошли.

Использование «РАЗРЕШЕННЫЕ» везде подряд

Ключевое слово РАЗРЕШЕННЫЕ в запросе включает проверку прав доступа на уровне записей (RLS). Это дорогостоящая операция, которая может в несколько раз замедлить запрос. Используйте его только там, где это действительно нужно — то есть только в запросах, которые видит пользователь, а не во внутренних расчётах.

Запросы без индексируемых условий

Запрос к регистру с условием по неиндексируемому реквизиту — это гарантированное полное сканирование таблицы. Убедитесь, что поля, по которым вы фильтруете, входят в индекс. Для регистров 1С автоматически создаёт индексы по измерениям, но не по ресурсам и реквизитам.

Игнорирование разделителей учёта

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

Чтение остатков в момент проведения документа

Классическая проблема при высокой нагрузке: несколько документов проводятся одновременно, каждый читает остатки, видит одну и ту же картину и записывает движения. В итоге остатки уходят в минус. Для решения используйте управляемые блокировки — это отдельная большая тема, но помнить о ней нужно всегда.

Итог: что делать прямо сейчас

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

Дальше идёте по приоритетам:

  • Сначала — правильность запросов (параметры виртуальных таблиц, запросы вне циклов)
  • Затем — агрегаты и итоги (включить, пересчитать, настроить)
  • Потом — индексы базы данных (перестроить, настроить регламент)
  • И только потом — структурные изменения (архивирование, разделение регистров)

Хорошая оптимизация — это системная работа, а не разовый подвиг. Настройте регламентные задания, мониторьте размеры таблиц, следите за новыми запросами в разработке. Тогда ваша 1С будет работать быстро годами, а не деградировать каждые полгода.

И помните: самая дорогая оптимизация — та, которую делают в панике, когда система уже встала. Профилактика всегда дешевле лечения.

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