#std792

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

1.

Не записывайте наборы записей регистров сведений и накопления в цикле по одной или нескольким записям. Это в несколько раз медленнее, чем запись одним набором.

В большинстве сценариев ориентируйтесь на порционную запись наборов примерно по 1000 записей.

2.

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

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

Кроме падения скорости, такой подход избыточно увеличивает журнал транзакций СУБД.

3.

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

Если нужно только добавить записи в пустой регистр, в методе Записать задайте параметру РежимЗамещения значение Ложь.

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

4.
4.1.

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

Неправильно

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

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

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

Правильно

Изменения записываются в регистр одним набором записей:

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

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

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

Неправильно

Наборы читаются и записываются в цикле:

Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт

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

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

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

Правильно

Изменения рассчитываются одним запросом и записываются одним набором:

Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт

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

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

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

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

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

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

  • вычислить новые записи без выгрузки исходных данных из СУБД в сервер 1С:Предприятия;
  • сравнить новые записи с текущими в обновляемом регистре;
  • выделить различия;
  • выбрать лишние записи для удаления;
  • выбрать недостающие и измененные записи для слияния.

Неправильно

Процедура ОбновитьСоставыИерархическихГруппПользователей(ГруппыПользователей) Экспорт

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

    Запрос = Новый Запрос;
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("ГруппыПользователей", ГруппыПользователей);

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

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

Правильно

Процедура ОбновитьСоставыИерархическихГруппПользователей(ГруппыПользователей) Экспорт

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

    Запрос = Новый Запрос;
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("ГруппыПользователей", ГруппыПользователей);

    РезультатыЗапроса = Запрос.ВыполнитьПакет();
    Если РезультатыЗапроса[0].Пустой() И РезультатыЗапроса[1].Пустой() Тогда
        Возврат;
    КонецЕсли;

    Блокировка = Новый БлокировкаДанных;

    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СоставыГруппПользователей");
    ЭлементБлокировки.ИсточникДанных = РезультатыЗапроса[0];
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("ГруппаПользователей", "ГруппаПользователей");
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Пользователь", "Пользователь");

    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СоставыГруппПользователей");
    ЭлементБлокировки.ИсточникДанных = РезультатыЗапроса[1];
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("ГруппаПользователей", "ГруппаПользователей");
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Пользователь", "Пользователь");

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

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

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

  • из-за регистратора ключ строки жестко задается полями Регистратор и НомерСтроки, режим Слияние недоступен;
  • в режиме Удаление платформа автоматически перенумеровывает НомерСтроки у оставшихся записей в рамках регистратора;
  • поле НомерСтроки следует использовать как счетчик строк в пределах регистратора, а не как прикладной порядок;
  • при вычислении изменений поле НомерСтроки нужно исключать из сравнения;
  • сначала формируйте набор (со сброшенным отбором) для Обновление из добавляемых и обновляемых строк в количестве не более числа удаляемых строк, с номерами удаляемых строк;
  • если после этого остались удаляемые строки, формируйте отдельный набор для Удаление из ключей этих строк;
  • если удаляемых строк не осталось, формируйте набор для Добавление (или Ложь) из оставшихся добавляемых и обновляемых строк без заполнения НомерСтроки (доступно с 1С:Предприятие 8.3.26).

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

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

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

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    Движения._ДемоОстаткиТоваровВМестахХранения.Записывать = Истина;

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

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

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

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

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

    РезультатыЗапроса = Запрос.ВыполнитьПакет();
    КлючиЛишнихЗаписей = РезультатыЗапроса[0].Выгрузить();
    НедостающиеЗаписи  = РезультатыЗапроса[1].Выгрузить();

    КоличествоЛишнихЗаписей = КлючиЛишнихЗаписей.Количество();
    КоличествоНедостающихЗаписей = НедостающиеЗаписи.Количество();
    Если КоличествоЛишнихЗаписей > КоличествоНедостающихЗаписей Тогда
        КоличествоОбновляемыхЗаписей = КоличествоНедостающихЗаписей;
    Иначе
        КоличествоОбновляемыхЗаписей = КоличествоЛишнихЗаписей;
    КонецЕсли;

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

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

    ИначеЕсли КоличествоЛишнихЗаписей < КоличествоНедостающихЗаписей Тогда
        НаборЗаписей = РегистрыНакопления._ДемоОстаткиТоваровВМестахХранения.СоздатьНаборЗаписей();
        НаборЗаписей.РасширенныеРежимыЗамещения = Истина;
        НаборЗаписей.Отбор.Сбросить();
        Для Индекс = КоличествоОбновляемыхЗаписей По КоличествоНедостающихЗаписей - 1 Цикл
            ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НедостающиеЗаписи[Индекс]);
        КонецЦикла;
        НаборЗаписей.Записать(РежимЗамещения.Добавление);
    КонецЕсли;

КонецПроцедуры
Источник

https://its.1c.ru/db/v8std#content:792