При работе с большими объемами данных, такими как 267 000 записей из Excel-файла, и попытке их загрузить в регистр сведений 1С, мы часто сталкиваемся с проблемой значительного замедления или даже полного зависания программы. Эта ситуация особенно актуальна, когда используемые подходы к работе с базой данных не оптимизированы для массовых операций. В этой статье мы подробно разберем, почему возникают такие проблемы, проанализируем типовые ошибки в коде и предложим эффективные методы для ускорения загрузки данных.
Наш регистр сведений, как выяснилось, состоит из трех измерений (два из которых являются ссылками на справочники, а одно — перечислением) и одного булевого ресурса. Именно такая структура, вкупе с неоптимизированным кодом, может привести к катастрофическим последствиям при загрузке сотен тысяч записей. Рассмотрим, как избежать этих проблем.
Основная причина медленной работы при загрузке большого объема данных кроется в неэффективном взаимодействии с базой данных внутри цикла обработки каждой строки. Давайте проанализируем типовой проблемный код, представленный в обсуждении:
// ... код чтения Excel ...
Для строкаТП = 0 По всегоСтрок Цикл
Если ПустаяСтрока(СокрЛП(МассивКолонок.Получить(1).Получить(строкаТП))) тогда
// Сообщить("Строка пустая "+ строкаТП); // <-- Проблемное место 1
Продолжить;
Иначе
НаименованиеРеквизита1 = МассивКолонок.Получить(0).Получить(строкаТП);
НаименованиеРеквизита2 = МассивКолонок.Получить(1).Получить(строкаТП);
НаименованиеРеквизита3 = МассивКолонок.Получить(2).Получить(строкаТП);
НаименованиеРеквизита3=СтрЗаменить(КонтрагентНаименование,"""","");
НаименованиеРеквизита4 = Булево(МассивКолонок.Получить(3).Получить(строкаТП));
// Поиск перечисления в цикле для каждой строки - Проблемное место 2
Для каждого ЭлементПеречисления Из Метаданные.Перечисления.нв_ВидыПечати.ЗначенияПеречисления Цикл
Если ЭлементПеречисления.Синоним = ВидПечатиНаименование Тогда
СсылкаНаПеречисление = Перечисления.нв_ВидыПечати[ЭлементПеречисления.Имя];
Прервать;
КонецЕсли;
КонецЦикла;
////Тут ниже запрос вытаскивает нужные данные по "НаименованиеРеквизита2", и сообщает, которые данные не нашел // <-- Проблемное место 3
------------
////Далее идет второй запрос, который вытаскивает нужные данные по "НаименованиеРеквизита3", которые данные не нашел, сообщает // <-- Проблемное место 3
---------------
мНаборЗаписей = РегистрыСведений.МойРегистрСведений.СоздатьНаборЗаписей();
// прочитали то, что есть в базе // <-- Проблемное место 4
мНаборЗаписей.Прочитать();
// заполняем свойства
НоваяЗапись = мНаборЗаписей.Добавить();
НоваяЗапись.Измерение1 = СсылкаНаПеречисление;
НоваяЗапись.Измерение2 = ФизическоеЛицо;
НоваяЗапись.Измерение3 = Контрагент;
НоваяЗапись.Ресурс1 = Напечатан;
мНаборЗаписей.Записать(); // <-- Проблемное место 4
КонецЕсли;
КонецЦикла;
Давайте разберем основные "проблемные места" в этом коде:
Сообщить() в цикле. Функция Сообщить() предназначена для информирования пользователя о некритичных событиях. При вызове ее для каждой из 267 000 записей, клиентское приложение пытается отобразить каждое сообщение, что приводит к заполнению буфера сообщений, огромной нагрузке на интерфейс и, как следствие, зависанию программы. Для массовых операций подобные уведомления следует либо полностью исключить, либо направлять в файл лога.ФизическоеЛицо и Контрагент) используются отдельные запросы внутри цикла, то для 267 000 записей будет выполнено минимум 534 000 запросов к базе данных (по два на каждую строку). Каждый запрос имеет свои накладные расходы на выполнение, что делает этот подход крайне неэффективным.мНаборЗаписей.Прочитать() и мНаборЗаписей.Записать() в цикле). Это критическая ошибка производительности. В каждой итерации цикла происходит следующее:
мНаборЗаписей = РегистрыСведений.МойРегистрСведений.СоздатьНаборЗаписей(); — создается пустой менеджер набора записей.мНаборЗаписей.Прочитать(); — из базы данных полностью считывается весь текущий набор записей регистра. Если регистр уже содержит десятки или сотни тысяч записей, это операция будет очень медленной.НоваяЗапись = мНаборЗаписей.Добавить(); — добавляется одна новая запись в уже считанный набор.мНаборЗаписей.Записать(); — весь набор записей (старые + одна новая) полностью перезаписывается в базу данных.Таким образом, для 267 000 записей регистр будет 267 000 раз полностью прочитан и 267 000 раз полностью перезаписан. Это создает колоссальную нагрузку на СУБД, вызывает длительные блокировки и неминуемо приводит к зависанию.
Для эффективной загрузки большого объема данных из Excel в регистр сведений мы должны перейти от поэлементной обработки и взаимодействия с базой данных к массовым операциям. Ключевой принцип — минимизировать количество обращений к СУБД и выполнять максимально возможный объем работы за одно действие.
Изначально файл Excel читается с использованием COM-объекта Excel.Application. Хотя этот метод работает, он имеет свои недостатки: требует установленного Microsoft Office, может зависать, и его выполнение на сервере не всегда оптимально. Более предпочтительным и универсальным способом является использование встроенного в 1С объекта ТабличныйДокумент.
Разберем по шагам, как это сделать:
Создадим функцию для чтения данных из файла Excel:
// Функция чтения данных из файла Excel
Функция ПрочитатьДанныеИзExcel(ПутьКФайлу)
Перем ТаблицаДанных;
Попытка
ТаблицаДокумент = Новый ТабличныйДокумент;
ТаблицаДокумент.Прочитать(ПутьКФайлу);
// Выгружаем данные с первого листа.
// Если Excel-файл содержит заголовки, можно указать ОбластьЯчеек
ТаблицаДанных = ТаблицаДокумент.Выгрузить(ТаблицаДокумент.Область(2, 1, ТаблицаДокумент.ВысотаТаблицы, ТаблицаДокумент.ШиринаТаблицы));
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Ошибка, , , "Ошибка при чтении файла Excel: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
Возврат ТаблицаДанных;
КонецФункции
// В основной обработке вызываем так:
// ТаблицаИзExcel = ПрочитатьДанныеИзExcel(ПутьКФайлу);
// Если ТаблицаИзExcel = Неопределено Тогда
// Возврат;
// КонецЕсли;
//
// Если ТаблицаИзExcel.Колонки.Количество() < 4 Тогда
// ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Ошибка, , , "В файле Excel недостаточно колонок.");
// Возврат;
// КонецЕсли;
//
// // Добавляем колонки в ТЗ для хранения ссылок, которые будем находить
// ТаблицаИзExcel.Колонки.Добавить("СсылкаИзмерение1", Новый ОписаниеТипов("ПеречислениеСсылка.нв_ВидыПечати"));
// ТаблицаИзExcel.Колонки.Добавить("СсылкаИзмерение2", Новый ОписаниеТипов("СправочникСсылка.ФизическиеЛица")); // Пример
// ТаблицаИзExcel.Колонки.Добавить("СсылкаИзмерение3", Новый ОписаниеТипов("СправочникСсылка.Контрагенты")); // Пример
Обратите внимание, что мы добавили в полученную ТаблицуЗначений новые колонки для ссылок, чтобы хранить в них найденные значения, не модифицируя исходные данные из Excel.
Вместо того чтобы искать каждую ссылку в цикле для каждой строки, мы должны сначала собрать все необходимые для поиска значения (например, наименования или коды справочников, синонимы перечислений) из Excel-таблицы, а затем выполнить массовый поиск этих ссылок.
// В начале процедуры загрузки, один раз:
СоответствиеВидовПечати = Новый Соответствие;
Для каждого ЭлементПеречисления Из Метаданные.Перечисления.нв_ВидыПечати.ЗначенияПеречисления Цикл
СоответствиеВидовПечати.Вставить(ЭлементПеречисления.Синоним, Перечисления.нв_ВидыПечати[ЭлементПеречисления.Имя]);
КонецЦикла;
Предположим, у нас есть наименования справочников в колонках "НаименованиеРеквизита2" и "НаименованиеРеквизита3" из Excel. Мы можем собрать все уникальные наименования, а затем одним запросом получить соответствующие ссылки.
// Собираем уникальные наименования для измерения 2 (например, ФизическиеЛица)
УникальныеНаименования2 = Новый Массив;
Для каждого СтрокаТЗ Из ТаблицаИзExcel Цикл
Если Не УникальныеНаименования2.Найти(СтрокаТЗ.КолонкаСНаименованием2) Тогда
УникальныеНаименования2.Добавить(СтрокаТЗ.КолонкаСНаименованием2);
КонецЕсли;
КонецЦикла;
// Аналогично для измерения 3 (например, Контрагенты)
УникальныеНаименования3 = Новый Массив;
Для каждого СтрокаТЗ Из ТаблицаИзExcel Цикл
Если Не УникальныеНаименования3.Найти(СтрокаТЗ.КолонкаСНаименованием3) Тогда
УникальныеНаименования3.Добавить(СтрокаТЗ.КолонкаСНаименованием3);
КонецЕсли;
КонецЦикла;
// Выполняем массовый запрос для получения ссылок (измерение 2)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СправочникФизическиеЛица.Ссылка КАК Ссылка,
| СправочникФизическиеЛица.Наименование КАК Наименование
|ИЗ
| Справочник.ФизическиеЛица КАК СправочникФизическиеЛица
|ГДЕ
| СправочникФизическиеЛица.Наименование В (&СписокНаименований)";
Запрос.УстановитьПараметр("СписокНаименований", УникальныеНаименования2);
РезультатЗапроса2 = Запрос.Выполнить().Выгрузить();
// Выполняем массовый запрос для получения ссылок (измерение 3)
Запрос.Текст =
"ВЫБРАТЬ
| СправочникКонтрагенты.Ссылка КАК Ссылка,
| СправочникКонтрагенты.Наименование КАК Наименование
|ИЗ
| Справочник.Контрагенты КАК СправочникКонтрагенты
|ГДЕ
| СправочникКонтрагенты.Наименование В (&СписокНаименований)";
Запрос.УстановитьПараметр("СписокНаименований", УникальныеНаименования3);
РезультатЗапроса3 = Запрос.Выполнить().Выгрузить();
// Теперь сопоставляем ссылки с нашей таблицей из Excel
Для каждого СтрокаТЗ Из ТаблицаИзExcel Цикл
// Перечисление
Если СоответствиеВидовПечати.ЕстьКлюч(СтрокаТЗ.КолонкаСНаименованием1) Тогда
СтрокаТЗ.СсылкаИзмерение1 = СоответствиеВидовПечати.Получить(СтрокаТЗ.КолонкаСНаименованием1);
Иначе
// Обработка случая, когда перечисление не найдено
ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Ошибка, , , "Не найдено значение перечисления '" + СтрокаТЗ.КолонкаСНаименованием1 + "' в строке " + СтрокаТЗ.НомерСтроки);
КонецЕсли;
// Справочник 2
НайденнаяСтрока2 = РезультатЗапроса2.Найти(СтрокаТЗ.КолонкаСНаименованием2, "Наименование");
Если НайденнаяСтрока2 <> Неопределено Тогда
СтрокаТЗ.СсылкаИзмерение2 = НайденнаяСтрока2.Ссылка;
Иначе
// Обработка случая, когда справочник не найден
ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Ошибка, , , "Не найден справочник ФизическиеЛица '" + СтрокаТЗ.КолонкаСНаименованием2 + "' в строке " + СтрокаТЗ.НомерСтроки);
КонецЕсли;
// Справочник 3
НайденнаяСтрока3 = РезультатЗапроса3.Найти(СтрокаТЗ.КолонкаСНаименованием3, "Наименование");
Если НайденнаяСтрока3 <> Неопределено Тогда
СтрокаТЗ.СсылкаИзмерение3 = НайденнаяСтрока3.Ссылка;
Иначе
// Обработка случая, когда справочник не найден
ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Ошибка, , , "Не найден справочник Контрагенты '" + СтрокаТЗ.КолонкаСНаименованием3 + "' в строке " + СтрокаТЗ.НомерСтроки);
КонецЕсли;
КонецЦикла;
// Создаем ТаблицуЗначений, соответствующую структуре регистра сведений
ТЗДляЗаписи = Новый ТаблицаЗначений;
ТЗДляЗаписи.Колонки.Добавить("Измерение1", Новый ОписаниеТипов("ПеречислениеСсылка.нв_ВидыПечати"));
ТЗДляЗаписи.Колонки.Добавить("Измерение2", Новый ОписаниеТипов("СправочникСсылка.ФизическиеЛица"));
ТЗДляЗаписи.Колонки.Добавить("Измерение3", Новый ОписаниеТипов("СправочникСсылка.Контрагенты"));
ТЗДляЗаписи.Колонки.Добавить("Ресурс1", Новый ОписаниеТипов("Булево"));
Для каждого СтрокаТЗ Из ТаблицаИзExcel Цикл
// Проверяем, что все ссылки найдены
Если СтрокаТЗ.СсылкаИзмере1 <> Неопределено
И СтрокаТЗ.СсылкаИзмерение2 <> Неопределено
И СтрокаТЗ.СсылкаИзмерение3 <> Неопределено Тогда
НоваяСтрока = ТЗДляЗаписи.Добавить();
НоваяСтрока.Измерение1 = СтрокаТЗ.СсылкаИзмерение1;
НоваяСтрова.Измерение2 = СтрокаТЗ.СсылкаИзмерение2;
НоваяСтрока.Измерение3 = СтрокаТЗ.СсылкаИзмерение3;
НоваяСтрока.Ресурс1 = СтрокаТЗ.КолонкаСБулевоЗначением; // Или НаименованиеРеквизита4
КонецЕсли;
КонецЦикла;
Если необходимо обновлять существующие записи, а не только добавлять новые, то перед записью можно использовать запрос для получения существующих записей регистра, объединить их с подготовленной ТЗ и создать на основе этого объединенного результата окончательную ТЗ для записи. Или же предварительно очистить регистр, если это допустимо.
После того как мы подготовили ТаблицуЗначений со всеми необходимыми данными и ссылками, мы можем использовать метод НаборЗаписей.Загрузить(ТаблицаЗначений) для массовой записи данных. Этот метод значительно более производителен, так как он выполняет все операции с базой данных за один или несколько транзакционных блоков, а не по одной записи.
// Создаем набор записей регистра
мНаборЗаписей = РегистрыСведений.МойРегистрСведений.СоздатьНаборЗаписей();
// Очищаем существующие записи, если это требуется (например, если загружаем данные "с нуля" или обновляем весь регистр)
// Если очистка всего регистра не нужна, и требуется лишь обновление или добавление,
// то этот шаг следует пропустить, или выполнить запрос на удаление только тех записей,
// которые будут перезаписаны, или объединить данные в ТЗ.
// Если регистр периодический и необходимо перезаписать записи за определенный период,
// то можно установить отбор по периоду перед Прочитать()/Записать().
// В данном случае, когда мы хотим просто заменить/добавить данные, если регистр не периодический
// и подразумевается полная перезапись всего набора, то перед загрузкой можно его очистить.
// Если нужно добавить новые записи и/или обновить существующие,
// и регистр не периодический (или отбор по измерениям уникален):
// мНаборЗаписей.Прочитать(); // Прочитываем текущий набор, если хотим сохранить существующие записи и добавить новые
// Далее нужно логику объединения ТЗ_ДляЗаписи с мНаборЗаписей, чтобы обновить существующие записи
// и добавить новые. Это сложнее, чем просто Загрузить.
// В простейшем случае, если мы перезаписываем все данные регистра,
// то сначала его можно очистить, если это допустимо:
// мНаборЗаписей.Отбор.Установить(Новый Структура()); // Устанавливаем отбор по всем измерениям, чтобы очистить все
// мНаборЗаписей.Записать(); // Запись пустого набора = очистка регистра
// Если мы хотим именно заменить все данные:
мНаборЗаписей.Очистить(); // Удалит все записи в регистре, если не установлен отбор
// Если регистр имеет измерения, по которым может быть отбор,
// например, по ФизическомуЛицу, и мы хотим обновить данные
// только для конкретного ФизическогоЛица, то нужно установить отбор:
// мНаборЗаписей.Отбор.Измерение2.Установить(СсылкаНаФизическоеЛицо);
// Загружаем подготовленную ТаблицуЗначений в набор записей
мНаборЗаписей.Загрузить(ТЗДляЗаписи);
// Записываем измененный набор в базу данных
мНаборЗаписей.Записать();
Обратите внимание, что метод Очистить() без установленного отбора очистит весь регистр. Если вам нужно только добавлять или обновлять записи, не удаляя другие, логика будет более сложной и потребует предварительного запроса к регистру, чтобы получить существующие записи и объединить их с новыми в ТаблицеЗначений.
Как мы уже выяснили, использование Сообщить() в цикле для большого количества записей крайне неэффективно. Вместо этого, для отслеживания прогресса и логирования ошибок мы рекомендуем:
ЗаписьЖурналаРегистрации().УстановитьТекстСостояния().
// Пример использования текстового файла для лога
ИмяФайлаЛога = "ЗагрузкаРС_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".log";
ПолныйПутьКФайлуЛога = КаталогВременныхФайлов() + ИмяФайлаЛога;
ТекстовыйДокументЛога = Новый ТекстовыйДокумент;
// ... внутри цикла обработки строк Excel ...
// вместо Сообщить("Строка пустая " + строкаТП);
ТекстовыйДокументЛога.ДобавитьСтроку("Строка пустая: " + строкаТП);
// ... если справочник не найден ...
ТекстовыйДокументЛога.ДобавитьСтроку("Ошибка: Не найден справочник '" + СтрокаТЗ.КолонкаСНаименованием2 + "' в строке " + СтрокаТЗ.НомерСтроки);
// ... после цикла ...
ТекстовыйДокументЛога.Записать(ПолныйПутьКФайлуЛога);
ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Информация, , , "Загрузка завершена. Лог в файле: " + ПолныйПутьКФайлуЛога);
Мы столкнулись с проблемой, что даже удаление 18 000 записей занимает 15 минут, что указывает на аналогичные ошибки в подходе к удалению. Если удаление выполняется в цикле по одной записи, это так же неэффективно. Для массового удаления необходимо использовать либо очистку всего набора записей (мНаборЗаписей.Очистить(); и мНаборЗаписей.Записать();), либо запрос, который удаляет записи по определенным условиям.
// Удаление всех записей регистра (если это допустимо)
МенеджерЗаписей = РегистрыСведений.МойРегистрСведений;
НаборДляОчистки = МенеджерЗаписей.СоздатьНаборЗаписей();
НаборДляОчистки.Очистить();
НаборДляОчистки.Записать();
// Или удаление записей по определенным условиям с помощью запроса
// (требует прав на интерактивное удаление объектов или выполнение через привилегированный режим)
Запрос = Новый Запрос;
Запрос.Текст =
"УДАЛИТЬ ИЗ
| РегистрСведений.МойРегистрСведений КАК РегистрСведенийМойРегистрСведений
|ГДЕ
| РегистрСведенийМойРегистрСведений.Измерение2 В (&СписокФизическихЛиц)"; // Пример условия
Запрос.УстановитьПараметр("СписокФизическихЛиц", МассивСсылокНаФизическиеЛицаДляУдаления);
Запрос.Выполнить();
Важно помнить, что удаление через запрос не вызывает обработчики событий объекта, поэтому этот метод следует использовать с осторожностью.
Важно отметить, что если вашей изначальной задачей было перемещение записей из одного регистра сведений одной базы данных в другую базу данных, существуют более подходящие и производительные инструменты, чем выгрузка в Excel и последующая загрузка. Рассмотрим их подробнее.
Это самый мощный и рекомендуемый способ для переноса данных между базами 1С, особенно если конфигурации одинаковые или очень похожие. Конвертация Данных (КД) позволяет создавать правила обмена, которые описывают, как объекты одной конфигурации соотносятся с объектами другой.
Разберем по шагам, как это работает:
MD8xExp.epf (или аналогичные средства) для выгрузки описаний структуры обеих баз данных (источника и приемника).Преимущества: Высокая производительность, надежность, автоматическое разрешение ссылок, возможность трансформации данных в процессе переноса, поддержка больших объемов данных.
Если требуется полностью программный обмен данными, например, через HTTP-сервисы, или если вы хотите создать собственный механизм без использования КД, форматы JSON или XML являются отличным выбором. 1С имеет встроенные функции для работы с этими форматами (ЧтениеJSON, ЗаписьJSON, ЧтениеXML, ЗаписьXML).
Разберем по шагам, как это работает:
// Пример выгрузки в JSON
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| МойРегистрСведений.Измерение1 КАК Измерение1,
| МойРегистрСведений.Измерение2 КАК Измерение2,
| МойРегистрСведений.Измерение3 КАК Измерение3,
| МойРегистрСведений.Ресурс1 КАК Ресурс1
|ИЗ
| РегистрСведений.МойРегистрСведений КАК МойРегистрСведений";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
СтрокаJSON = ЗаписатьJSON(РезультатЗапроса);
// Далее сохраняем СтрокаJSON в файл или передаем по сети
НаборЗаписей.Загрузить().
// Пример загрузки из JSON
// Предположим, у нас есть СтрокаJSON с данными регистра
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
ДанныеИзJSON = ЧтениеJSON.Прочитать();
ЧтениеJSON.Закрыть();
// ДанныеИзJSON теперь представляет собой ТаблицуЗначений или Массив
// Далее используем подготовку данных и НаборЗаписей.Загрузить(ДанныеИзJSON)
Преимущества: Полный контроль над процессом обмена, гибкость, подходит для интеграции с внешними системами. Отличная альтернатива для простой передачи данных без сложных преобразований.
Для сложных сценариев, когда данные из Excel необходимо объединить с существующими данными в базе, выполнить сложные преобразования или найти ссылки, запросы с использованием временных таблиц являются очень мощным инструментом.
Разберем по шагам, как это работает:
ТабличныйДокумент.ТаблицаЗначений. В тексте запроса эта таблица может быть использована как временная.СОЕДИНЕНИЕ (ЛЕВОЕ, ВНУТРЕННЕЕ и т.д.) для сопоставления данных из временной таблицы с данными из таблиц справочников, документов или регистров сведений в базе данных.
// Пример использования запроса для получения ссылок и подготовки данных для регистра
// Предположим, ТаблицаИзExcel уже содержит колонки с наименованиями и булевым значением.
// Необходимо добавить в нее колонки для ссылок, как это было описано ранее.
// Здесь мы используем ее как источник данных для временной таблицы.
// Создаем менеджер временных таблиц
МВТ = Новый МенеджерВременныхТаблиц;
// Помещаем данные из Excel во временную таблицу
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст =
"ПОМЕСТИТЬ ВТ_ДанныеExcel
|ИЗ
| &ТаблицаИзExcel КАК ТаблицаИзExcel
|;
|
|ВЫБРАТЬ
| ТаблицаИзExcel.КолонкаСНаименованием1 КАК НаименованиеПеречисления,
| ТаблицаИзExcel.КолонкаСНаименованием2 КАК НаименованиеФизЛица,
| ТаблицаИзExcel.КолонкаСНаименованием3 КАК НаименованиеКонтрагента,
| ТаблицаИзExcel.КолонкаСБулевоЗначением КАК БулевоРесурс
|ИЗ
| ВТ_ДанныеExcel КАК ТаблицаИзExcel";
Запрос.УстановитьПараметр("ТаблицаИзExcel", ТаблицаИзExcel); // Передаем нашу ТЗ как параметр
Запрос.Выполнить();
// Теперь основной запрос, который сопоставляет данные и получает ссылки
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст =
"ВЫБРАТЬ
| Перечисления.нв_ВидыПечати.Ссылка КАК Измерение1,
| СправочникФизическиеЛица.Ссылка КАК Измерение2,
| СправочникКонтрагенты.Ссылка КАК Измерение3,
| ВТ_ДанныеExcel.БулевоРесурс КАК Ресурс1
|ИЗ
| ВТ_ДанныеExcel КАК ВТ_ДанныеExcel
| ЛЕВОЕ СОЕДИНЕНИЕ Перечисления.нв_ВидыПечати КАК Перечисления.нв_ВидыПечати
| ПО ВТ_ДанныеExcel.НаименованиеПеречисления = Перечисления.нв_ВидыПечати.Синоним
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК СправочникФизическиеЛица
| ПО ВТ_ДанныеExcel.НаименованиеФизЛица = СправочникФизическиеЛица.Наименование
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК СправочникКонтрагенты
| ПО ВТ_ДанныеExcel.НаименованиеКонтрагента = СправочникКонтрагенты.Наименование
|ГДЕ
| Перечисления.нв_ВидыПечати.Ссылка ЕСТЬ НЕ NULL
| И СправочникФизическиеЛица.Ссылка ЕСТЬ НЕ NULL
| И СправочникКонтрагенты.Ссылка ЕСТЬ НЕ NULL"; // Отбираем только те, для которых найдены все ссылки
ТЗДляЗаписиВРегистр = Запрос.Выполнить().Выгрузить();
// Далее используем ТЗДляЗаписиВРегистр с мНаборЗаписей.Загрузить()
// ...
Обращаем ваше внимание на необходимость соответствия типов данных в колонках ТаблицыЗначений, передаваемой в запрос, и полей временной таблицы. Если типы не совпадают, могут возникнуть ошибки или замедление производительности.
НаборЗаписей.Загрузить().Применяя эти оптимизированные подходы, вы сможете значительно сократить время загрузки данных из Excel в регистр сведений, предотвратить зависание программы и обеспечить стабильную работу вашей системы 1С даже с очень большими объемами информации.