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

#std792

Область применения: управляемое приложение, мобильное приложение, обычное приложение.

1. Не рекомендуется записывать наборы записей регистров сведений и накоплений в цикле по одной или нескольким записям. Это в несколько раз медленнее по сравнению с записью регистра одним набором. В большинстве случаев следует ориентироваться на порционную запись наборов из 1000 записей.

2. Рекомендуется избегать перезаписи большого набора, в котором меняется не более 30% записей. Вместо этого следует записывать только изменения.

Перезапись набора приводит к удалению всех записей по отбору набора записей и вставке всех новых записей набора, включая те, которые не менялись. Это в несколько раз медленнее по сравнению с добавлением, обновлением и удалением только измененных записей, если измененных записей не более 30% от всех записей в наборе. Помимо этого, избыточно растет журнал транзакций СУБД (пропорционально количеству удалений и вставки записей).

3. Для оптимальной записи регистров следует применять режимы замещения в сочетании с вычислением измененных записей.

В частном случае, когда нужно только добавить записи в пустой регистр, достаточно в методе Записать набора записей задать параметру РежимЗамещения значение Ложь (добавление). В остальных случаях, рекомендуется использовать режимы замещения Слияние, Удаление (начиная с версии платформы 1С:Предприятие 8.3.26) и Обновление (начиная с версии платформы 1С:Предприятие 8.3.27). Они позволяют обрабатывать записи пакетно, порциями.

4. Примеры.

4.1. Состав добавляемых, обновляемых и удаляемых записей известен и требуется применить эти изменения к базе данных.

Неправильно записывать наборы записей в цикле:

Блокировка = Новый БлокировкаДанных();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПользовательскиеНастройки");
ЭлементБлокировки.УстановитьЗначение("Пользователь", ПользовательСсылка);

НачатьТранзакцию();
Попытка
    Блокировка.Заблокировать();
    Для Каждого ЗначениеНастройки Из Настройки Цикл
        УдаляемыеЗаписи = РегистрыСведений.ПользовательскиеНастройки.СоздатьНаборЗаписей();
        УдаляемыеЗаписи.Отбор.ИдентификаторКоманды.Установить(ЗначениеНастройки.ИдентификаторКоманды);
        УдаляемыеЗаписи.Отбор.Пользователь.Установить(ПользовательСсылка);
        УдаляемыеЗаписи.Записать();
    КонецЦикла;
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки

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

Блокировка = Новый БлокировкаДанных();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПользовательскиеНастройки");
ЭлементБлокировки.УстановитьЗначение("Пользователь", ПользовательСсылка);

НачатьТранзакцию();
Попытка
    Блокировка.Заблокировать();
    УдаляемыеЗаписи = РегистрыСведений.ПользовательскиеНастройки.СоздатьНаборЗаписей();
    Для Каждого ЗначениеНастройки Из Настройки Цикл
        УдаляемаяЗапись = УдаляемыеЗаписи.Добавить();
        УдаляемаяЗапись.ИдентификаторКоманды = ЗначениеНастройки.ИдентификаторКоманды;
        УдаляемаяЗапись.Пользователь = ПользовательСсылка;
    КонецЦикла;
    УдаляемыеЗаписи.Записать(РежимЗамещения.Удаление);
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки

4.2. Заполнение значения нового реквизита (или ресурса) регистра в отложенном обработчике обновления. Обрабатывается порция данных, зарегистрированных для обновления: если значение еще не заполнено, тогда заполнить, иначе не менять.

Неправильно читать и записывать наборы записей в цикле:

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

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

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

4.3. Обновление части записей в независимом регистре сведений.  При записи карточки объекта данные меняются частично.

Объект уже записан в базу данных (транзакция может быть еще не зафиксирована), поэтому применяем запрос, чтобы:

Например, неправильно:

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

Правильно:

Процедура ОбновитьСоставыИерархическихГруппПользователей(ГруппыПользователей) Экспорт
    
    ТекстЗапроса =
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей,
    |    СоставыГруппПользователей.Пользователь КАК Пользователь
    |ИЗ
    |    РегистрСведений.ИерархияГруппПользователей КАК ГруппыДляОбновления1
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
    |        ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДляОбновления1.Родитель)
    |            И (ГруппыДляОбновления1.ГруппаПользователей В (&ГруппыПользователей))
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИерархияГруппПользователей КАК ГруппыДляОбновления2
    |            ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ИерархияГруппПользователей КАК НижестоящиеГруппы
    |            ПО (НижестоящиеГруппы.Родитель = ГруппыДляОбновления2.Родитель)
    |                И (ГруппыДляОбновления2.ГруппаПользователей В (&ГруппыПользователей))
    |            ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыПользователей.Состав КАК ГруппыПользователейСостав
    |            ПО (ГруппыПользователейСостав.Ссылка = НижестоящиеГруппы.ГруппаПользователей)
    |        ПО (ГруппыДляОбновления2.Родитель = СоставыГруппПользователей.ГруппаПользователей)
    |            И (ГруппыПользователейСостав.Пользователь = СоставыГруппПользователей.Пользователь)
    |ГДЕ
    |    ГруппыПользователейСостав.Пользователь ЕСТЬ NULL
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    ГруппыДляОбновления.Родитель КАК ГруппаПользователей,
    |    ГруппыПользователейСостав.Пользователь КАК Пользователь,
    |    НЕ ГруппыДляОбновления.Родитель.ПометкаУдаления
    |        И НЕ ГруппыПользователейСостав.Пользователь.ПометкаУдаления
    |        И НЕ ГруппыПользователейСостав.Пользователь.Недействителен КАК Используется
    |ИЗ
    |    РегистрСведений.ИерархияГруппПользователей КАК ГруппыДляОбновления
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ИерархияГруппПользователей КАК НижестоящиеГруппы
    |        ПО (НижестоящиеГруппы.Родитель = ГруппыДляОбновления.Родитель)
    |            И (ГруппыДляОбновления.ГруппаПользователей В (&ГруппыПользователей))
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыПользователей.Состав КАК ГруппыПользователейСостав
    |        ПО (ГруппыПользователейСостав.Ссылка = НижестоящиеГруппы.ГруппаПользователей)
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
    |        ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДляОбновления.Родитель)
    |            И (СоставыГруппПользователей.Пользователь = ГруппыПользователейСостав.Пользователь)
    |ГДЕ
    |    (СоставыГруппПользователей.Пользователь ЕСТЬ NULL
    |            ИЛИ ЕСТЬNULL(СоставыГруппПользователей.Используется, ЛОЖЬ) <> (НЕ ГруппыДляОбновления.Родитель.ПометкаУдаления
    |                И НЕ ГруппыПользователейСостав.Пользователь.ПометкаУдаления
    |                И НЕ ГруппыПользователейСостав.Пользователь.Недействителен))";
    
    Запрос = Новый Запрос;
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("ГруппыПользователей", ГруппыПользователей);
    
    РезультатыЗапроса = Запрос.ВыполнитьПакет();
    Если РезультатыЗапроса[0].Пустой() И РезультатыЗапроса[1].Пустой() Тогда
        Возврат;
    КонецЕсли;
    
    Блокировка = Новый БлокировкаДанных;
    
    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СоставыГруппПользователей");
    ЭлементБлокировки.ИсточникДанных = РезультатыЗапроса[0];
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("ГруппаПользователей", "ГруппаПользователей");
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Пользователь", "Пользователь");
    
    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СоставыГруппПользователей");
    ЭлементБлокировки.ИсточникДанных = РезультатыЗапроса[1];
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("ГруппаПользователей", "ГруппаПользователей");
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Пользователь", "Пользователь");
    
    НачатьТранзакцию();
    Попытка
        Блокировка.Заблокировать();
        РезультатыЗапроса = Запрос.ВыполнитьПакет();
        Если Не РезультатыЗапроса[0].Пустой() Тогда
            НаборЗаписей = РегистрыСведений.СоставыГруппПользователей.СоздатьНаборЗаписей();
            НаборЗаписей.Загрузить(РезультатыЗапроса[0].Выгрузить());
            НаборЗаписей.Записать(РежимЗамещения.Удаление);
        КонецЕсли;
        Если Не РезультатыЗапроса[1].Пустой() Тогда
            НаборЗаписей = РегистрыСведений.СоставыГруппПользователей.СоздатьНаборЗаписей();
            НаборЗаписей.Загрузить(РезультатыЗапроса[1].Выгрузить());
            НаборЗаписей.Записать(РежимЗамещения.Слияние);
        КонецЕсли;
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение;
    КонецПопытки;
КонецПроцедуры

4.4. Обновление части записей в регистрах, подчиненных регистратору. При перепроведении данные меняются частично.

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

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

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

Обычное решение:

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

Оптимальное решение:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Запрос = Новый Запрос;
    Запрос.УстановитьПараметр("Документ", Ссылка);
    Запрос.Текст =
    "ВЫБРАТЬ
    |    ТекущийРегистр.Регистратор КАК Регистратор,
    |    ТекущийРегистр.НомерСтроки КАК НомерСтроки
    |ИЗ
    |    РегистрНакопления._ДемоОстаткиТоваровВМестахХранения КАК ТекущийРегистр
    |        ЛЕВОЕ СОЕДИНЕНИЕ Документ._ДемоОприходованиеТоваров КАК ТекущийДокумент
    |            ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ._ДемоОприходованиеТоваров.Товары КАК ТекущийДокументТовары
    |            ПО (ТекущийДокумент.Ссылка = &Документ)
    |                И (ТекущийДокументТовары.Ссылка = ТекущийДокумент.Ссылка)
    |        ПО (ТекущийРегистр.Активность)
    |            И (ТекущийРегистр.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход))
    |            И (ТекущийДокумент.Дата = ТекущийРегистр.Период)
    |            И (ТекущийДокумент.Организация = ТекущийРегистр.Организация)
    |            И (ТекущийДокумент.МестоХранения = ТекущийРегистр.МестоХранения)
    |            И (ТекущийДокументТовары.Номенклатура = ТекущийРегистр.Номенклатура)
    |            И (ТекущийДокументТовары.Количество = ТекущийРегистр.Количество)
    |ГДЕ
    |    ТекущийРегистр.Регистратор = &Документ
    |    И ТекущийДокумент.Ссылка ЕСТЬ NULL
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ТекущийДокумент.Ссылка КАК Регистратор,
    |    ТекущийДокумент.Дата КАК Период,
    |    ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход) КАК ВидДвижения,
    |    ТекущийДокумент.Организация КАК Организация,
    |    ТекущийДокумент.МестоХранения КАК МестоХранения,
    |    ТекущийДокументТовары.Номенклатура КАК Номенклатура,
    |    ТекущийДокументТовары.Количество КАК Количество
    |ИЗ
    |    Документ._ДемоОприходованиеТоваров КАК ТекущийДокумент
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ._ДемоОприходованиеТоваров.Товары КАК ТекущийДокументТовары
    |        ПО (ТекущийДокумент.Ссылка = &Документ)
    |            И (ТекущийДокументТовары.Ссылка = ТекущийДокумент.Ссылка)
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления._ДемоОстаткиТоваровВМестахХранения КАК ТекущийРегистр
    |        ПО (ТекущийРегистр.Активность)
    |            И (ТекущийРегистр.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход))
    |            И (ТекущийРегистр.Период = ТекущийДокумент.Дата)
    |            И (ТекущийРегистр.Организация = ТекущийДокумент.Организация)
    |            И (ТекущийРегистр.МестоХранения = ТекущийДокумент.МестоХранения)
    |            И (ТекущийРегистр.Номенклатура = ТекущийДокументТовары.Номенклатура)
    |            И (ТекущийРегистр.Количество = ТекущийДокументТовары.Количество)
    |ГДЕ
    |    ТекущийРегистр.ВидДвижения ЕСТЬ NULL";
    
    РезультатыЗапроса = Запрос.ВыполнитьПакет();
    КлючиЛишнихЗаписей = РезультатыЗапроса[0].Выгрузить();
    НедостающиеЗаписи  = РезультатыЗапроса[1].Выгрузить();
    
    КоличествоЛишнихЗаписей = КлючиЛишнихЗаписей.Количество();
    КоличествоНедостающихЗаписей = НедостающиеЗаписи.Количество();
    Если КоличествоЛишнихЗаписей > КоличествоНедостающихЗаписей Тогда
        КоличествоОбновляемыхЗаписей = КоличествоНедостающихЗаписей;
    Иначе
        КоличествоОбновляемыхЗаписей = КоличествоЛишнихЗаписей;
    КонецЕсли;
    
    Если КоличествоОбновляемыхЗаписей > 0 Тогда
        НаборЗаписей = РегистрыНакопления._ДемоОстаткиТоваровВМестахХранения.СоздатьНаборЗаписей();
        НаборЗаписей.РасширенныеРежимыЗамещения = Истина;
        НаборЗаписей.Отбор.Сбросить();
        Для Индекс = 0 По КоличествоОбновляемыхЗаписей - 1 Цикл
            НоваяЗапись = НаборЗаписей.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяЗапись, НедостающиеЗаписи[Индекс]);
            НоваяЗапись.НомерСтроки = КлючиЛишнихЗаписей[Индекс].НомерСтроки;
        КонецЦикла;
        НаборЗаписей.Записать(РежимЗамещения.Обновление);
    КонецЕсли;
    
    Если КоличествоЛишнихЗаписей > КоличествоНедостающихЗаписей Тогда
        НаборЗаписей = РегистрыНакопления._ДемоОстаткиТоваровВМестахХранения.СоздатьНаборЗаписей();
        НаборЗаписей.РасширенныеРежимыЗамещения = Истина;
        НаборЗаписей.Отбор.Сбросить();
        Для Индекс = КоличествоОбновляемыхЗаписей По КоличествоЛишнихЗаписей - 1 Цикл
            ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), КлючиЛишнихЗаписей[Индекс]);
        КонецЦикла;
        НаборЗаписей.Записать(РежимЗамещения.Удаление);
        
    ИначеЕсли КоличествоЛишнихЗаписей < КоличествоНедостающихЗаписей Тогда
        НаборЗаписей = РегистрыНакопления._ДемоОстаткиТоваровВМестахХранения.СоздатьНаборЗаписей();
        НаборЗаписей.РасширенныеРежимыЗамещения = Истина;
        НаборЗаписей.Отбор.Сбросить();
        Для Индекс = КоличествоОбновляемыхЗаписей По КоличествоНедостающихЗаписей - 1 Цикл
            ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НедостающиеЗаписи[Индекс]);
        КонецЦикла;                                      
        НаборЗаписей.Записать(РежимЗамещения.Добавление);
    КонецЕсли;
    
КонецПроцедуры