Разработка и Конфигурация · 9 мин
Что быстрее в 1С: менеджер записи или набор записей
Сравниваем менеджер записи и набор записей в 1С: скорость, блокировки, контроль данных. Когда каждый способ записи регистра быстрее и безопаснее.
Вопрос «что быстрее — менеджер записи или набор записей» возникает у каждого разработчика 1С, который работает с регистрами сведений. Короткий ответ: набор записей почти всегда быстрее при массовой записи, а менеджер записи удобнее для точечной работы с одной строкой. Но разница — не только в скорости: эти объекты по-разному ведут себя с блокировками, отборами и контролем уникальности.
Менеджер записи (объект типа РегистрСведенийМенеджерЗаписи) представляет одну запись регистра. Набор записей (РегистрСведенийНаборЗаписей) — это коллекция записей с отбором, которая читается и записывается в базу целиком, одним обращением. Именно количество обращений к СУБД и определяет основную разницу в производительности.
Ниже разберём, как устроена запись в обоих случаях, где реальный выигрыш по времени, какие подводные камни у каждого подхода и как проверить результат на своей базе.
Как устроена запись через менеджер записи
Менеджер записи создаётся через объектную модель: вы заполняете измерения и ресурсы, затем вызываете метод Записать(). Каждый вызов — это отдельное обращение к серверу СУБД: вставка или обновление одной строки таблицы регистра.
МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.Валюта = ВалютаСсылка;
МенеджерЗаписи.Курс = 95.5;
МенеджерЗаписи.Записать();
Если нужно записать тысячу строк в цикле, будет выполнена тысяча отдельных SQL-операций. На файловой базе это заметно, на клиент-серверной — ещё сильнее из-за сетевых задержек и накладных расходов на транзакции. Кроме того, если цикл обёрнут в одну явную транзакцию, все промежуточные блокировки удерживаются до её завершения.
Дополнительный нюанс: менеджер записи перед записью может неявно читать существующую строку (например, при вызове Прочитать() или при проверках), что добавляет ещё одно обращение к базе на каждую итерацию.
Как работает набор записей и почему он быстрее
Набор записей накапливает строки в памяти и записывает их одной операцией. При записи с замещением (параметр по умолчанию Истина) платформа удаляет старые строки по отбору и вставляет новые пакетно. Это принципиально меньше обращений к СУБД.
НаборЗаписей = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Период.Установить(ДатаКурса);
Для Каждого СтрокаДанных Из ДанныеКурсов Цикл
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ДатаКурса;
НоваяЗапись.Валюта = СтрокаДанных.Валюта;
НоваяЗапись.Курс = СтрокаДанных.Курс;
КонецЦикла;
НаборЗаписей.Записать();
При загрузке, например, курсов валют за месяц по десятку валют выигрыш по времени может быть кратным: вместо сотен одиночных вставок выполняется одна пакетная операция. Чем больше строк, тем заметнее разница.
Сравнение по ключевым параметрам
Выбор между двумя объектами стоит делать не только по скорости. Ниже сопоставление по практически значимым критериям.
| Критерий | Менеджер записи | Набор записей |
|---|---|---|
| Обращения к СУБД | Одно на каждую строку | Одно на весь пакет |
| Скорость массовой записи | Низкая, растёт линейно с числом строк | Высокая за счёт пакетной операции |
| Точечная запись одной строки | Удобен, код короче | Избыточен, требует отбора |
| Риск затереть чужие данные | Минимальный — только своя строка | Высокий при записи с замещением без точного отбора |
| Обработчики ПередЗаписью/ПриЗаписи | Вызываются на каждую запись | Вызываются один раз на набор |
| Блокировки | По одной строке, но много подряд | На диапазон отбора, короткое время удержания |
Отдельно учитывайте обработчики событий. Если в модуле набора записей регистра есть логика в ПередЗаписью или ПриЗаписи, она выполнится один раз для набора и многократно для менеджера записи. Иногда это аргумент в пользу набора, иногда — источник ошибок, если обработчик рассчитан на построчную логику.
Когда что выбирать
Одна-две строки, точечное обновление, интерактивная работа. Ограничение: медленно в циклах по сотням и тысячам записей.
Пакетная загрузка данных по известному ключу отбора: период, документ, организация. Ограничение: при замещении затирает всё в рамках отбора.
Добавление строк без удаления существующих (Записать(Ложь)). Ограничение: при совпадении ключей получите ошибку уникальности.
Блокировки и параллельная работа
В многопользовательской среде скорость — не единственный фактор. Менеджер записи в длинном цикле внутри транзакции удерживает блокировки на каждой изменённой строке до конца транзакции. При конкурентной работе других пользователей с тем же регистром это повышает вероятность взаимоблокировок и ошибок «Конфликт блокировок».
Набор записей блокирует диапазон по отбору, но делает это на короткое время одной операции. На практике пакетная запись реже приводит к конфликтам, чем тысяча последовательных одиночных вставок в одной транзакции. Однако широкий отбор (например, по целому периоду) может заблокировать данные, которые меняют другие сеансы.
Типичные ошибки при использовании обоих подходов
Самая разрушительная ошибка с набором записей — вызов Записать() без установленного отбора. Платформа считает, что вы работаете со всем регистром, и при замещении удалит все существующие записи, записав только те, что в наборе. Восстановление возможно только из резервной копии.
Типичная ошибка с менеджером записи — использование его в цикле по большой выборке без необходимости. Разработчик пишет «как привык», и регламентная загрузка, которая могла бы занять секунды, работает минуты. Вторая частая проблема — чтение через менеджер записи в цикле вместо одного запроса: это тот же класс ошибки «запрос в цикле», только через объектную модель.
Как измерить разницу на своей базе
Теоретические рассуждения полезно подтвердить замером. Платформа даёт для этого простой инструмент — ТекущаяУниверсальнаяДатаВМиллисекундах() или замер через ОценкаПроизводительности, если используется БСП.
- 1Создайте копию базы или используйте тестовый регистр с типовой структурой
- 2Подготовьте тестовый массив данных, например 1000 строк
- 3Запишите данные циклом через менеджер записи, замерив время до и после цикла
- 4Очистите регистр и запишите те же данные набором записей с отбором, также с замером
- 5Сравните результаты и повторите замер 2–3 раза для исключения случайных пиков
- 6Проверьте наложенные блокировки через консоль СУБД или технологический журнал при параллельной нагрузке
НачалоЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах();
// ... код записи ...
Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоЗамера;
Сообщить("Время записи: " + Длительность + " мс");
Замер делайте на базе, близкой по объёму к продуктивной: на пустой таблице разница менее выразительна, чем на регистре с миллионами строк, где добавляются затраты на поддержание индексов.
Как проверить результат
Набор записей заметно быстрее на сотнях и тысячах строк
Разницы нет — возможно, запись идёт по одной строке или узкое место в другом месте кода
Совпадает с ожидаемым, старые данные по отбору корректно замещены
Записей меньше или больше ожидаемого — проверьте отбор и режим замещения
Конфликтов нет или они единичны
Регулярные конфликты — сокращайте транзакцию или переносите запись на нерабочее время
Частые вопросы
Можно ли использовать набор записей для записи одной строки?
Можно, но в этом нет выигрыша: накладные расходы на создание набора и установку отбора сопоставимы с работой менеджера записи. Для одиночной строки менеджер записи даёт более короткий и читаемый код.
Что делать, если нужно добавить строки, не удаляя существующие?
Используйте набор записей с вызовом Записать(Ложь) — запись без замещения. Учтите, что при совпадении значений измерений с уже существующими записями платформа выдаст ошибку нарушения уникальности индекса.
Почему запись набора иногда работает медленно, хотя строк немного?
Частая причина — широкий отбор или его отсутствие: платформа удаляет и перезаписывает большой массив данных. Также проверьте обработчики событий регистра и подписки на события — тяжёлая логика в них выполняется при каждой записи.
Влияет ли режим разделения данных на выбор подхода?
В сервисных моделях с разделителями платформа сама добавляет разделители в отбор, но принцип не меняется: пакетная запись набора быстрее цикла менеджеров записи. Дополнительно учитывайте, что в разделённом режиме ошибка с отбором затронет данные только текущей области.
Есть ли альтернатива обоим способам для очень больших объёмов?
Для загрузки действительно больших массивов обычно комбинируют подходы: пишут порциями по несколько тысяч записей через набор записей внутри одной транзакции или разбивают на отдельные транзакции. Это ограничивает размер блокировок и журнала транзакций СУБД.
Что важно запомнить
Набор записей быстрее при массовой записи за счёт одного обращения к базе, менеджер записи удобнее для одиночных строк. Главный риск набора — запись с замещением без точного отбора, главный риск менеджера — медленные циклы и долгие блокировки. Перед оптимизацией продуктивного кода проверьте поведение на копии базы.