При обработке сторонних файлов больших объемов (например, CSV-файлов на 400 000 строк и более) разработчики часто сталкиваются с проблемами производительности и некорректного поиска данных. Метод Найти() объекта ТаблицаЗначений может работать медленно или пропускать существующие значения, а попытка просмотреть такую таблицу в режиме отладки приводит к аварийному завершению работы платформы 1С. Разберем по шагам, почему возникают эти проблемы и как построить эффективный алгоритм сопоставления данных.
Часто в Excel или текстовых редакторах строка успешно находится, а метод Найти() в 1С возвращает Неопределено. Проанализируем основные причины такого поведения:
\r\n. При стандартном считывании текста в конце значения колонки может оставаться невидимый символ возврата каретки \r (Символы.ВК). Excel при импорте игнорирует его, а 1С воспринимает как часть значения строки.\uFEFF), первый символ первой строки будет содержать невидимый байт, что нарушит точность поиска для первой колонки.СокрЛП() не всегда удаляет специфические невидимые символы.Попытка просмотреть таблицу значений на 400 000 элементов в окне вычисления выражений или табло приводит к тому, что платформа пытаются сформировать графическое представление всего массива в памяти клиента. Это вызывало быструю нехватку оперативной памяти сеанса и завершение работы 1С. Для работы с такими объемами данных отладку следует выполнять на некрупных выборках (например, первые 1000 строк).
Если поиск необходимо выполнить огромное количество раз (например, несколько миллионов обращений), метод Найти() или поиск по запросу к ТЗ окажутся слишком медленными. Самым быстрым способом в 1С является структура Соответствие, обеспечивающая выборку со скоростью O(1).
Рассмотрим пример создания индекса в памяти на основе объекта Соответствие:
ИндексДанных = Новый Соответствие;
// В процессе чтения CSV заполняем ключ и значение
Пока ЧтениеCSV.Прочитать() Цикл
КлючПоиска = СокрЛП(ЧтениеCSV.Получить(0)); // Например, артикул или ИНН
// Если ключи уникальны, сохраняем значение или структуру
ИндексДанных.Вставить(КлючПоиска, ЧтениеCSV.Получить(1));
КонецЦикла;
// Мгновенный поиск за O(1)
ИскомоеЗначение = ИндексДанных.Получить(ИскомыйКлюч);
Если ИскомоеЗначение <> Неопределено Тогда
// Совпадение найдено
КонецЕсли;
Если ключи в файле могут повторяться, в качестве значения ключа структуры Соответствие следует сохранять Массив, в который добавляются все соответствующие строки.
Если алгоритм требует использования именно таблицы значений и индексации через ТЗ.Индексы.Добавить(), необходимо обязательно задавать строгую квалификацию типов колонок при создании ТЗ.
Посмотрим на пример правильной типизации колонок:
ТЗДанных = Новый ТаблицаЗначений;
// Задаем точную длину строки
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Строка"));
КвалификаторыСтроки = Новый КвалификаторыСтроки(150, ДопустимаяДлина.Переменная);
ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТипов, , КвалификаторыСтроки);
ТЗДанных.Колонки.Добавить("КодПоиска", ОписаниеТипаСтрока);
ТЗДанных.Колонки.Добавить("Значение", ОписаниеТипаСтрока);
// Индексируем колонку с точным типом
ТЗДанных.Индексы.Добавить("КодПоиска");
Если данные необходимо сопоставлять со сложными условиями или группировками, загруженную таблицу значений можно передать в запрос через временную таблицу. При этом в запросе также важно правильно ограничить тип строки с помощью функции ВЫРАЗИТЬ().
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(ТЗ.КодПоиска КАК СТРОКА(150)) КАК КодПоиска,
| ТЗ.Значение КАК Значение
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &ТаблицаДанных КАК ТЗ
|
|ИНДЕКСИРОВАТЬ ПО
| КодПоиска
|;
|
|ВЫБРАТЬ
| ВТ_Данные.КодПоиска,
| ВТ_Данные.Значение
|ИЗ
| ВТ_Данные КАК ВТ_Данные
|ГДЕ
| ВТ_Данные.КодПоиска = &ИскомыйКод";
Запрос.УстановитьПараметр("ТаблицаДанных", ТЗДанных);
Запрос.УстановитьПараметр("ИскомыйКод", ИскомыйКод);
Результат = Запрос.Выполнить();
СтрЗаменить(Строка, Символы.ВК, "").ЧтениеXML для поэтапной обработки файла вместо загрузки полного дерева в память. На каждом шаге чтения XML выполняйте быстрое сопоставление через ранее подготовленное Соответствие.Соответствие используйте функцию ВРЕГ() или НРЕГ() для искомого значения и ключей индекса.