К статье
Практический материал

Разработка и Конфигурация · 9 мин

Что быстрее в 1С: менеджер записи или набор записей

Сравниваем менеджер записи и набор записей в 1С: скорость, блокировки, контроль данных. Когда каждый способ записи регистра быстрее и безопаснее.

Вопрос «что быстрее — менеджер записи или набор записей» возникает у каждого разработчика 1С, который работает с регистрами сведений. Короткий ответ: набор записей почти всегда быстрее при массовой записи, а менеджер записи удобнее для точечной работы с одной строкой. Но разница — не только в скорости: эти объекты по-разному ведут себя с блокировками, отборами и контролем уникальности.

Менеджер записи (объект типа РегистрСведенийМенеджерЗаписи) представляет одну запись регистра. Набор записей (РегистрСведенийНаборЗаписей) — это коллекция записей с отбором, которая читается и записывается в базу целиком, одним обращением. Именно количество обращений к СУБД и определяет основную разницу в производительности.

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

Как устроена запись через менеджер записи

Менеджер записи создаётся через объектную модель: вы заполняете измерения и ресурсы, затем вызываете метод Записать(). Каждый вызов — это отдельное обращение к серверу СУБД: вставка или обновление одной строки таблицы регистра.

МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();

МенеджерЗаписи.Период = ТекущаяДатаСеанса();

МенеджерЗаписи.Валюта = ВалютаСсылка;

МенеджерЗаписи.Курс = 95.5;

МенеджерЗаписи.Записать();

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

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

Как работает набор записей и почему он быстрее

Набор записей накапливает строки в памяти и записывает их одной операцией. При записи с замещением (параметр по умолчанию Истина) платформа удаляет старые строки по отбору и вставляет новые пакетно. Это принципиально меньше обращений к СУБД.

НаборЗаписей = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();

НаборЗаписей.Отбор.Период.Установить(ДатаКурса);

Для Каждого СтрокаДанных Из ДанныеКурсов Цикл

НоваяЗапись = НаборЗаписей.Добавить();

НоваяЗапись.Период = ДатаКурса;

НоваяЗапись.Валюта = СтрокаДанных.Валюта;

НоваяЗапись.Курс = СтрокаДанных.Курс;

КонецЦикла;

НаборЗаписей.Записать();

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

Сравнение по ключевым параметрам

Выбор между двумя объектами стоит делать не только по скорости. Ниже сопоставление по практически значимым критериям.

КритерийМенеджер записиНабор записей
Обращения к СУБДОдно на каждую строкуОдно на весь пакет
Скорость массовой записиНизкая, растёт линейно с числом строкВысокая за счёт пакетной операции
Точечная запись одной строкиУдобен, код корочеИзбыточен, требует отбора
Риск затереть чужие данныеМинимальный — только своя строкаВысокий при записи с замещением без точного отбора
Обработчики ПередЗаписью/ПриЗаписиВызываются на каждую записьВызываются один раз на набор
БлокировкиПо одной строке, но много подрядНа диапазон отбора, короткое время удержания

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

Когда что выбирать

Менеджер записи

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

Набор записей с отбором

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

Набор записей без замещения

Добавление строк без удаления существующих (Записать(Ложь)). Ограничение: при совпадении ключей получите ошибку уникальности.

Блокировки и параллельная работа

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

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

Типичные ошибки при использовании обоих подходов

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

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

Типичные ошибки
01
Набор записей без отбора с замещением — удаляются все записи регистра
02
Менеджер записи в цикле по тысячам строк — линейный рост времени и блокировок
03
Запись набора с замещением при неполных данных — строки, не попавшие в набор, теряются
04
Игнорирование обработчиков событий — логика ПередЗаписью ведёт себя иначе для набора и для одиночной записи
05
Запись набора без замещения при возможных дублях — исключение по уникальности индекса

Как измерить разницу на своей базе

Теоретические рассуждения полезно подтвердить замером. Платформа даёт для этого простой инструмент — ТекущаяУниверсальнаяДатаВМиллисекундах() или замер через ОценкаПроизводительности, если используется БСП.

Порядок замера
  1. 1
    Создайте копию базы или используйте тестовый регистр с типовой структурой
  2. 2
    Подготовьте тестовый массив данных, например 1000 строк
  3. 3
    Запишите данные циклом через менеджер записи, замерив время до и после цикла
  4. 4
    Очистите регистр и запишите те же данные набором записей с отбором, также с замером
  5. 5
    Сравните результаты и повторите замер 2–3 раза для исключения случайных пиков
  6. 6
    Проверьте наложенные блокировки через консоль СУБД или технологический журнал при параллельной нагрузке
НачалоЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах();

// ... код записи ...

Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоЗамера;

Сообщить("Время записи: " + Длительность + " мс");

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

Контрольные точки

Как проверить результат

Время массовой записи
Норма

Набор записей заметно быстрее на сотнях и тысячах строк

Тревожный признак

Разницы нет — возможно, запись идёт по одной строке или узкое место в другом месте кода

Количество записей после записи
Норма

Совпадает с ожидаемым, старые данные по отбору корректно замещены

Тревожный признак

Записей меньше или больше ожидаемого — проверьте отбор и режим замещения

Ошибки блокировок у пользователей
Норма

Конфликтов нет или они единичны

Тревожный признак

Регулярные конфликты — сокращайте транзакцию или переносите запись на нерабочее время

Частые вопросы

Можно ли использовать набор записей для записи одной строки?

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

Что делать, если нужно добавить строки, не удаляя существующие?

Используйте набор записей с вызовом Записать(Ложь) — запись без замещения. Учтите, что при совпадении значений измерений с уже существующими записями платформа выдаст ошибку нарушения уникальности индекса.

Почему запись набора иногда работает медленно, хотя строк немного?

Частая причина — широкий отбор или его отсутствие: платформа удаляет и перезаписывает большой массив данных. Также проверьте обработчики событий регистра и подписки на события — тяжёлая логика в них выполняется при каждой записи.

Влияет ли режим разделения данных на выбор подхода?

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

Есть ли альтернатива обоим способам для очень больших объёмов?

Для загрузки действительно больших массивов обычно комбинируют подходы: пишут порциями по несколько тысяч записей через набор записей внутри одной транзакции или разбивают на отдельные транзакции. Это ограничивает размер блокировок и журнала транзакций СУБД.

Итог

Что важно запомнить

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