Скорость закачки с EXCEL при работе с большими файлами

Поставлена задача уменьшить время загрузки данных с EXCEL. Пока ждал ответа от разработчиков ядра, сам начал копать всё, что угодно.
ЗАДАЧА решена, с чем спешу поделиться.

1. Файл должен быть закачан в МАССИВ весь сразу!!!!!! У меня 27000 строк за 0,1-0,5 сек. СОМ-объект можно сразу отключить(закрыть). Замечание: метод VALUE отрабатывает в 5 раз быстрее, чем TEXT, ввиду того, что не преобразует значение в текст;

 

ЗначениеСтр = ExcelЛист.Range(ExcelЛист.Cells(1,1), ExcelЛист.Cells(СтрокаПо,КолонкаПО));
Данные = ЗначениеСтр.Value.Выгрузить();
 

2. Если его необходимо загрузить в ТабличныйДокумент, то загрузку можно сделать или по строкам, или по колонкам. По времени загрузки строки или колонки грузятся почти одинаково, но строк больше же. Так вот надо грузить по тому, что меньше. У меня колонок 20, а строк 27000. В итоге, приблизительно в 100 раз быстрее загрузился в ТабличныйДокумент при использовании метода «по колонкам» (строка первая). А можно и не грузить в ТД, не тратить время, а начать обрабатывать сразу МАССИВ.

Выше написанное значит, что распространенный в инете пример работы с EXCEL с перебором каждой ячейки работает намного медленнее, чем вышеописанный. Постараюсь выложить на Инфостарт решение

Для Column = КолонкаС По КолонкаПО Цикл
Для Row = СтрокаС По СтрокаПО Цикл
ТД.Область("R" + Формат(Row, "ЧГ=")+"C" + Формат(Column, "ЧГ=")).Текст = Данные[Column-1][Row-1];
КонецЦикла;
КонецЦикла;
 
 

Если такой метод не совсем корректный — напишите, плиз. Может, есть и еще более быстрый, к примеру, не понятный пока для меня метод, используемый в ядре 1С без использования СОМ-объектов вообще: ФАЙЛ/ОТКРЫТЬ/*.XLS*

31 Comments

  1. flyDrag

    Было бы хорошо увидеть этот пример в готовой обработке

    Reply
  2. Samarin

    1. Есть новая фишка в платформе 8.3.6. Попробуйте ее посмотреть.

    ТабДок = Новый ТабличныйДокумент;

    ТабДок.Прочитать(«C:My DocumentsТаблица1.mxl»);

    Описание:

    Считывает табличный документ из файла.

    Позволяет считывать табличный документ из файла табличного документа Microsoft Excel 97 — 2010 ( *.xls и *.xlsx) или электронной таблицы OpenOffice Calc ( *.ods).

    2. Посмотреть и попробовать применить многопоточную обработку:

    http://infostart.ru/public/306865/

    Если изыскания будут успешны — с меня плюс, лайк или что тут раздают))

    Reply
  3. alonehobo
    ТД.Область(«R» + Формат(Row, «ЧГ=»)+»C» + Формат(Column, «ЧГ=»)).Текст = Данные[Column-1][Row-1];

    Можно просто использовать числа для указания адреса ячейки, без лишнего форматирования:

    ТД.Область(Row, Column).Текст = Данные[Column-1][Row-1];

    Reply
  4. webester

    Неудобно прерывать вашу радость от найденного решения, но… <Зануда MODE> поиском пользоваться не пробовали?</Зануда MODE>

    http://infostart.ru/public/20090/ с достаточно бурными обсуждением, замерами и сравнениями в комментариях.

    Reply
  5. ybatiaev

    (2) Samarin, Этот метод (ТД.Прочитать()) и ранее был и в старых версиях, Но он работает только в толстом клиенте. А у всех сейчас уже тонкие

    Reply
  6. ybatiaev

    (3) alonehobo, это был тестовый пример… спешил поделиться

    А функция ФОРМАТ() у меня использовалась для считывания значения ячеек, а некоторые ячейки имели число с разделителями триад пробелом.

    Раньше использовал метод не VALUE (это работает так, как надо) , а TEXT, а он преобразовывал число 1 333 в строку «1 333». Ну далее Вы понимаете…

    ну вот на старых обработках и экспериментировал… забыл убрать это убожество :-)))

    Reply
  7. ybatiaev

    (4) webester,

    спасибо за замечание, по ссылкам я «ходил» … но вот не нашел того, что записывать в ТД быстрее оказалось по колонкам (первый цикл), а потом по строкам (цикл внутри). Если поменять это, т.е. сначала взять строку и разобрать её по колонкам, потом другую… работает на файлах с большим количеством записей намного дольше. ЭТОГО НЕ НАШЕЛ. С чем и поделился. Ну может всего прочитать невозможно или промелькнуло мимо за ненадобностью тогда.

    Reply
  8. ybatiaev

    (2) Samarin, Про потоки ИНТЕРЕСНО. Мне это еще со старых времен работы с С++ известно было… почитаю!!! Спасибо!

    Reply
  9. Samarin

    (5) Во-первых, в изменениях к 8.3.6 по данному поводу написано ясно, что в предыдущих версиях подобной возможности не было. Во-вторых, правильная работа в клиент-серверном режиме и через веб-клиент подразумевает правильный подход к работе с файлами: получение файлов осуществляется на клиентской части, далее данные передаются на сервер, обработка данных производится на серверной стороне.

    Reply
  10. qwinter

    (4) webester, ну так чукча не читатель, чукча писатель © )))))

    Reply
  11. qwinter

    (7)

    но вот не нашел того, что записывать в ТД быстрее оказалось по колонкам (первый цикл), а потом по строкам (цикл внутри).

    а построителем или СКД еще быстрее))

    Reply
  12. Yashazz

    Батенька, ну вы уж поиском-то и правда, воспользуйтесь… А ещё про обмен через COMSafeArray и ADO почитайте)

    Reply
  13. Идальго

    27000 строк это вроде совсем немного (скорее это очень мало). Странно, что у вас оно слишком долго читает.

    Reply
  14. LavinVadik

    вот готовое решение на v7, прикуруть к 8-ке не стоставит большого труда

    http://infostart.ru/public/329372/

    Reply
  15. qwinter

    (14) LavinVadik, на восьмерке давно есть в разы более универсальные.

    Reply
  16. wbazil
    Reply
  17. ybatiaev

    (15) qwinter, Дайте ссылку плиз. Читает да, теперь быстро. 27000 строк по 30 колонок — 0,1 сек

    тут рассовывается по документам и справочникам долго… сейчас с этим разберусь тоже

    Reply
  18. qwinter
  19. rus128

    Все понимаю.

    Не понимаю только, почему «закачка», а не «загрузка» или (еще лучше) «импорт».

    Reply
  20. cool.vlad4

    (2) Samarin, да, только этой штукой пользоваться пока нельзя. выбора листа нет, при чтении больших файлов (свыше 50000 строк) все падает и ничего не читает

    Reply
  21. cool.vlad4

    Могу еще и изменение существующего файла быстрое подсказать как делать, то что можно через ADO это и так понятно, но зачастую была проблема считать значения из файла с формулами и потом туда что-нибудь записать и т.п. можно сформировать ТЗ (или любой другой набор данных), выгрузить в другой excel файл средствами платформы, потом считать этот второй файл через ADO в Recordset и выгрузить в нужную область в нужный файл Excel через CopyFromRecordset. Самое смешное , что все эти записи в файлы, считывание на порядок быстрее чем запись значений через Excel.Application

    Reply
  22. Serg O.

    здорово, что нашел такую функцию….

    но ускорение только на 1/2 так делается

    скорость «разбора» строк — тоже иногда очень долго идет…

    самый быстрый способ чтения из Excel это программный COPY-PAST

    c использованием WScript.Shell

    «посылкой» команды Ctrl+C (на выделенный диапазон ячеек Excel)

    и Ctrl+V в таблицу 1С (лучше в ТабличныйДокумент)

    WSHShell.SendKeys(«#k8SjZc9Dxkc») WSHShell.SendKeys(«#k8SjZc9Dxkv»)

    см. http://forum.infostart.ru/forum26/topic75936/

    дополнительные команды управления книгой Excel из 1C см. http://www.1c-h.ru/?p=238

    Reply
  23. ybatiaev

    (13) Идальго, Добрый день!

    Если не тяжело — напишите ГДЕ почитать про скорость закачки большого числа строк для документов.

    Вот, к примеру? в файле присутствует 5500 документов (в ~53000 строках в EXCEL)

    Сделал следующее:

    1. Чтение из файла в массив ДАННЫХ с определением границ и промежуточных данных, потом отключаю СОМ с EXCEL;

    ———- 8 секунд ————————————- ОК!

    2. Работаю уже с массивом ДАННЫХ;

    3. Проверяю/создаю номенклатуру, причем записываю в массивы данные по ней (мНоменклТХТ — текстовое представление номенклатуры, мНоменклСсылка — ссылку на номенклатуру). При обработке новой строки ищу в массиве подобную номенклатуру (нашел индекс элемента) и с другого массива вытаскиваю по индексу значение(ссылка) и её уже подставляю в дополнительную ячейку в массив ДАННЫЕ (т.е. не дергаю саму базу, если ссылка на номенклатуру была «запомнена» ранее, подобие «КЭШа»);

    4. Параллельно создаю записи в ТЧ обработки со списком документов(несколько строк файла — это один документ, другие — другой и т.д.). Тут же проверяю/создаю КОНТРАГЕНТА и ДОГОВОР. Механизм как в 3 пункте («КЭШ»);

    5. Также определяю СтавкуНДС;

    6. В итоге получаю массив ДАННЫХ со списком документов с УЖЕ созданными и приготовленными КОНТРАГЕНТАМИ, ДОГОВОРАМИ, НОМЕНКЛАТУРОЙ, СТАВКОЙ НДС (ссылки для подстановки в документ);

    ———- 1590 сек (27 минут) —————— нуууу… приемлемо… ОК!

    7. Теперь я просто пытаюсь создать сами документы — вот тут то и большая проблема, точнее большие тормоза. Т.е. есть всё, что надо, все найдено или создано. И я могу все проверить и подправить, если что. Но документы создавались 17(!) часов. Не могу пока понять ПОЧЕМУ.

    ———- 17 часов ———- КОНКРЕТНО НЕ ОК 🙁 ————————-

    ну да, по сравнению с предыдущей обработкой, которая создает ЭТО за 2,5 суток(60 часов) — это решение, но все же. В среднем на создание одного документа в связке с одной Сч-ф потрачено 12(!) секунд. И это не на рабочей базе, там будет в 2 раза дольше.

    Если есть что подсказать — киньте ссылку на то, где и что почитать. Поругайте меня, если что не знаю, но помогите!

    Reply
  24. ybatiaev

    (11) qwinter, Добрый день!

    сделал чтение файла 1-8 сек

    первичную обработку более имения приемлемую — 53000 строк за 8 минут, в ней поиск/создание контрагентов. договоров, номенклатуры и т.п.

    Не подскажите ли чукче-писателю как убыстрить создание документов. По замерам производительности именно тут ТОРМОЗА. Фоновые задания не подходят, т.к. конфигурацию вскрывать нельзя. Асинхронные вызовы копаю сейчас.

    Хоть в каком направлении копать? Количество документов в структуре файла до 24000, количество обрабатываемых строк файла до 60000. Основные тормоза в месте НовыйДокумент.Записать()

    Буду очень признателен

    Reply
  25. Идальго

    (23) я не знаю где вам почитать, но, думаю, что на инфостарте много информации. Как я понял, собственно чтение достаточно быстро идёт, по крайней мере вас устраивает… Замечу лишь, что при создании и записи новых объектов, я бы использовал транзакции, а также ссылку нового. Ну и проверок всяких поменьше делал (т.е. работать должны только нужные), если они есть (при записи и/или проведении).

    По поводу документов — наверное нужно выяснить, что конкретно занимает больше всего времени и оптимизировать процедуры. Т.е. смотреть и замерять в отладчике (в первую очередь), а так же использовать технологический журнал (тоже смотреть счетчики всякие) и SQL Profiler.

    Вообще у вас проблема наверное какая нибудь банальная, м.б. файловая подсистема барахлит, а может в коде много чего лишнего или неоптимального делается (посмотрите, что происходит в модуле документа, м.б. подписки какие дикие потом еще выполняются). Главное копать, не бросать это дело. Тогда по-любому разберётесь и почините свою загрузку.

    Как идею, можете рассмотреть вариант загрузки в несколько потоков. Т.е., можно файл разбить на части и в нескольких сеансах его обрабатывать, если конечно это возможно.

    Reply
  26. ybatiaev

    (25) Идальго, добрый день!

    именно потоками и начал вчера заниматься. Вообще обнаружил, что именно НовыйДокумент.Записать() и тратит время самое большее, в 20-100 раз большее, чем всё остальное. Про подписки — поразбираюсь, но не думаю. Подписки на создание документов по моему не работают.

    Про многопоточность — в МАНах написано, что текст обработки должен быть в общем модуле, а конфигурация закрытая. Сейчас сделал убыстрение ОБЩЕЕ в 5 раз. Доделаю и покопаюсь с многопоточностью. Я бы разбил на 2 потока минимум — создание Документа(Реализация, Поступление, ПКО или вписка) в одном, а счет-фактуры в другом (после создания самого документа)… но не получилось пока, а так еще бы время уменьшилась бы в 2 раза максимум.

    Сегодня гляну в планы обмена…. может там что-то по новым объектам пишется дополнительно

    а по поводу проверок:

    так я и разбил на 2 этапа: 1 — это закачка, все проверки и поиск/создание всех объектов. В итоге у меня получается таблица со всеми УЖЕ НУЖНЫМИ ссылками, перечислениями и данными.

    и 2 этап — это создание НовыхДокументов на основании этой таблицы (пока в этом траблзы)

    1-й этап — общее время на ~25000 записей от 3,5 до 27 минут, что принципе нормально

    2-й этап — более 17 часов (со старой обработкой было около 60 часов)

    еще заметил, что в замерах производительности когда в накопленных вызовах менее 24000, то обрабатываются быстро(5-7 вызовов в секунду), а дальше 2 в секунду… Что-то накапливается и переполняется в КЭШе что-ли…. копаюсь еще

    Reply
  27. user970630

    Спасибо. Ёмко и по делу.

    Reply
  28. ybatiaev

    (27) Если это не сарказм, то ещё хочу поделиться опытом. В один документ не более 10000 записей нужно записывать в табличную часть. Иначе будут жуткие тормоза. У меня, при ёмких закачках быстрее было создать 6 документов по ~10000 записей, чем один с 60000.

    Reply
  29. user970630

    (28)

    Интересно. Спасибо. Получается с большим массивом работать дольше чем с одинаковым количеством строк разбитых на несколько файлов… Интересно а многопоточность есть? Как будет быстрее?

    Еще интересно какой результат будет если файл меньше, например 1000 строк. Уместно его делить и, если да, то на сколько частей.

    Reply
  30. ybatiaev

    (29) Пробовал. Если документ должен содержать ~10000 строк и меньше, то быстрее закачать одним разом.

    С многопоточностью выгодно работать, если в файле 100 000 строк, но это записывается в 20 документов, то:

    1. будет время на общий разбор и подготовку массива итоговых документов;

    2. начать запись сразу всех 20 документов. Кто-то писал на инфостарте, что не более 10 потоков, не проверял;

    3. Многопоточность работает в клиент-серверном варианте. В файловом только один. Хотя может сразу не разобрался корректно или сейчас что-то изменилось что-то.

    Если Вы пишите в лог всё, что делается, то Вам необходимо предусмотреть УПРАВЛЯЕМЫЕ блокировки файла логов. Иначе будет просто вылет с места, в котором Вы пытаетесь записать что-то, если файл занят другим потоком.

    Reply
  31. user970630

    (30)

    Это уже как-то сложнее ) Много условий надо обработать.

    Я грузил несколько раз файлы, но не очень большие. Хотя все относительно… Самый большой был в 1500 строк и и где-то 20+ столбцов. Причем клиент хотел чтобы все было у него на старом компе (в смысле работа проходил). Просидел у него почти целый день, пока сделали как он хотел…

    Поэтому и интересуюсь увеличением скорости загрузки. Еще раз спасибо. В следующий раз буду пробовать Ваш метод.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *