358 документов
← К списку

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

страница

#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.Родитель)     |            И (ГруппыДляОбновления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 Цикл             ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НедостающиеЗаписи[Индекс]);         КонецЦикла;                                               НаборЗаписей.Записать(РежимЗамещения.Добавление);     КонецЕсли;      КонецПроцедуры