Как быстро найти строку в CSV-файле большой размерности в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При обработке сторонних файлов больших объемов (например, CSV-файлов на 400 000 строк и более) разработчики часто сталкиваются с проблемами производительности и некорректного поиска данных. Метод Найти() объекта ТаблицаЗначений может работать медленно или пропускать существующие значения, а попытка просмотреть такую таблицу в режиме отладки приводит к аварийному завершению работы платформы 1С. Разберем по шагам, почему возникают эти проблемы и как построить эффективный алгоритм сопоставления данных.

Почему 1С «не видит» строки, которые находят сторонние редакторы

Часто в Excel или текстовых редакторах строка успешно находится, а метод Найти() в 1С возвращает Неопределено. Проанализируем основные причины такого поведения:

  1. Служебные символы переноса строк: CSV-файлы, сформированные в ОС Windows, часто содержат комбинацию \r\n. При стандартном считывании текста в конце значения колонки может оставаться невидимый символ возврата каретки \r (Символы.ВК). Excel при импорте игнорирует его, а 1С воспринимает как часть значения строки.
  2. Скрытый маркер BOM: Если CSV сохранен в UTF-8 с маркером BOM (\uFEFF), первый символ первой строки будет содержать невидимый байт, что нарушит точность поиска для первой колонки.
  3. Лишние и неразрывные пробелы: По краям и искомой строки, и значения в таблице могут присутствовать пробелы или неразрывные пробелы (Unicode 160). Обычная функция СокрЛП() не всегда удаляет специфические невидимые символы.
  4. Неограниченная длина строк в ТЗ: Если колонка таблицы значений создана без явного указания длины (неограниченная строка), индексы таблицы значений могут работать некорректно или полностью игнорироваться платформой.
  5. Смешение алфавитов (омоглифы): Названия или артикулы могут содержать внешне идентичные символы кириллицы и латиницы (например, буквы «С» и «C»), имеющие разные коды.

Почему 1С падает при отладке больших таблиц

Попытка просмотреть таблицу значений на 400 000 элементов в окне вычисления выражений или табло приводит к тому, что платформа пытаются сформировать графическое представление всего массива в памяти клиента. Это вызывало быструю нехватку оперативной памяти сеанса и завершение работы 1С. Для работы с такими объемами данных отладку следует выполнять на некрупных выборках (например, первые 1000 строк).

Способы ускорения поиска и варианты решения

Вариант 1. Использование объекта Соответствие (хеш-таблица O(1))

Если поиск необходимо выполнить огромное количество раз (например, несколько миллионов обращений), метод Найти() или поиск по запросу к ТЗ окажутся слишком медленными. Самым быстрым способом в 1С является структура Соответствие, обеспечивающая выборку со скоростью O(1).

Рассмотрим пример создания индекса в памяти на основе объекта Соответствие:


ИндексДанных = Новый Соответствие;

// В процессе чтения CSV заполняем ключ и значение
Пока ЧтениеCSV.Прочитать() Цикл
    КлючПоиска = СокрЛП(ЧтениеCSV.Получить(0)); // Например, артикул или ИНН
    
    // Если ключи уникальны, сохраняем значение или структуру
    ИндексДанных.Вставить(КлючПоиска, ЧтениеCSV.Получить(1));
КонецЦикла;

// Мгновенный поиск за O(1)
ИскомоеЗначение = ИндексДанных.Получить(ИскомыйКлюч);
Если ИскомоеЗначение <> Неопределено Тогда
    // Совпадение найдено
КонецЕсли;

Если ключи в файле могут повторяться, в качестве значения ключа структуры Соответствие следует сохранять Массив, в который добавляются все соответствующие строки.

Вариант 2. Явная типизация колонок Таблицы Значений

Если алгоритм требует использования именно таблицы значений и индексации через ТЗ.Индексы.Добавить(), необходимо обязательно задавать строгую квалификацию типов колонок при создании ТЗ.

Посмотрим на пример правильной типизации колонок:


ТЗДанных = Новый ТаблицаЗначений;

// Задаем точную длину строки
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Строка"));
КвалификаторыСтроки = Новый КвалификаторыСтроки(150, ДопустимаяДлина.Переменная);
 ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТипов, , КвалификаторыСтроки);

ТЗДанных.Колонки.Добавить("КодПоиска", ОписаниеТипаСтрока);
ТЗДанных.Колонки.Добавить("Значение", ОписаниеТипаСтрока);

// Индексируем колонку с точным типом
ТЗДанных.Индексы.Добавить("КодПоиска");

Вариант 3. Использование Запроса и Временных Таблиц

Если данные необходимо сопоставлять со сложными условиями или группировками, загруженную таблицу значений можно передать в запрос через временную таблицу. При этом в запросе также важно правильно ограничить тип строки с помощью функции ВЫРАЗИТЬ().


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВЫРАЗИТЬ(ТЗ.КодПоиска КАК СТРОКА(150)) КАК КодПоиска,
    |	ТЗ.Значение КАК Значение
    |ПОМЕСТИТЬ ВТ_Данные
    |ИЗ
    |	&ТаблицаДанных КАК ТЗ
    |
    |ИНДЕКСИРОВАТЬ ПО
    |	КодПоиска
    |;
    |
    |ВЫБРАТЬ
    |	ВТ_Данные.КодПоиска,
    |	ВТ_Данные.Значение
    |ИЗ
    |	ВТ_Данные КАК ВТ_Данные
    |ГДЕ
    |	ВТ_Данные.КодПоиска = &ИскомыйКод";

Запрос.УстановитьПараметр("ТаблицаДанных", ТЗДанных);
Запрос.УстановитьПараметр("ИскомыйКод", ИскомыйКод);
Результат = Запрос.Выполнить();

Рекомендации по оптимизации сопоставления

  1. Очищайте строки от спецсимволов: При считывании файла применяйте функции удаления символов возврата каретки: СтрЗаменить(Строка, Символы.ВК, "").
  2. Используйте потоковое чтение: При сопоставлении с деревьями XML используйте объект ЧтениеXML для поэтапной обработки файла вместо загрузки полного дерева в память. На каждом шаге чтения XML выполняйте быстрое сопоставление через ранее подготовленное Соответствие.
  3. Переводите ключи в единый регистр: Если поиск должен быть регистронезависимым, при формировании ключей в Соответствие используйте функцию ВРЕГ() или НРЕГ() для искомого значения и ключей индекса.
← На главную