Имя: Пароль:
1C
1С v8
Медленный экспорт в Excel
0 apd123
 
18.11.14
15:50
Есть регистр сведений с примерно 35К записей, его нужно экспортировать в эксель.
Делаю так:

Процедура ПриОткрытииНаСервере()
    имяФайла = "C:\excel-export-test.xlsx";
Попытка
    Попытка
        ExcelПриложение = Новый COMОбъект("Excel.Application");
    Исключение
        Сообщить("Ошибка при запуске Microsoft Excel."
        + Символы.ПС + ОписаниеОшибки(), СтатусСообщения.Внимание);
        Возврат;
    КонецПопытки;
    Книга = ExcelПриложение.WorkBooks.Add();
    Лист = Книга.WorkSheets(1);
    
    Лист.Cells(1, 1).Value = "Заголовок 1";
//     ...
    Лист.Cells(1, 49).Value = "Заголовок 49";

    Выборка = РегистрыСведений.Данные.Выбрать();
    Счетчик = 2;
    Пока Выборка.Следующий() Цикл
        ТекущаяСтрока = Выборка.ПолучитьМенеджерЗаписи();
        Лист.Cells(Счетчик, 1).Value = ТекущаяСтрока.Поле1;
        Лист.Cells(Счетчик, 2).Value = ТекущаяСтрока.Поле2;
        Лист.Cells(Счетчик, 3).Value = ТекущаяСтрока.Поле3;
        Лист.Cells(Счетчик, 4).Value = ТекущаяСтрока.Поле4;
        Лист.Cells(Счетчик, 5).Value = ТекущаяСтрока.Поле5;
        Лист.Cells(Счетчик, 13).Value = ТекущаяСтрока.Поле13;
        Лист.Cells(Счетчик, 14).Value = ТекущаяСтрока.Поле14;
        Лист.Cells(Счетчик, 20).Value = ТекущаяСтрока.Поле20;
        Лист.Cells(Счетчик, 29).Value = ТекущаяСтрока.Поле29;
        
        Счетчик = Счетчик + 1;
    КонецЦикла;

    Книга.SaveAs(имяФайла);
    ExcelПриложение.Quit();
    Сообщить("Файл выгружен успешно: " + имяФайла );
Исключение
    Сообщить("Ошибка записи данных файла :" + имяФайла);
    Сообщить(ОписаниеОшибки());
    Попытка
        ExcelПриложение.Quit();
    Исключение
    КонецПопытки;
КонецПопытки;
КонецПроцедуры


Обработка выполняется полтора часа. Вот так выглядит замер производительности http://i.imgur.com/6wrs2yh.png
Видно что почти все время уходит на запись значений в ячейки. При этом тип содержимого (там есть и числа и даты и строки) на скорость почти никак не влияет.

На мой взгляд полтора часа это как-то дофига, учитывая что никаких расчетов не происходит, просто запись в файл, при том что итоговый экселевский файл весит примерно 2 мегабайта. Или это нормально? Если нет, то куда копать?
1 Wobland
 
18.11.14
15:52
а вывести список не пробовал?
2 sapphire
 
18.11.14
15:52
(0) А табличный документ тоже сохраняет долго?
3 Wobland
 
18.11.14
15:53
> ТекущаяСтрока = Выборка.ПолучитьМенеджерЗаписи();
бохмой
4 sapphire
 
18.11.14
15:54
(3) Да уж...
5 sapphire
 
18.11.14
15:55
банан долбобей нервно курит :)
6 Wobland
 
18.11.14
15:55
да какой дивный регистр. так и вспоминаются ресурсы у одного РН (остатки обуви): Размер40, Размер42...
7 Wobland
 
18.11.14
15:56
и полтора часа висит при открытии? а мне нравится
8 13_Mult
 
18.11.14
15:57
А кода "Счетчик" заканчивает считать?
9 sapphire
 
18.11.14
15:58
(7) Да это видать компания Штирлиц...
зато название РС какое "Данные" :)))
10 Wobland
 
18.11.14
15:58
(8) на 94й минуте матча
11 Wobland
 
18.11.14
15:59
+(9) поле. русское поооле...
12 sapphire
 
18.11.14
16:00
Да и исчо это фсио на сервере....
13 13_Mult
 
18.11.14
16:01
Началась, дискотека
14 Wobland
 
18.11.14
16:02
ну ладно, поправим автора ;)
Видно что почти все время уходит на чтение значений
15 H A D G E H O G s
 
18.11.14
16:04
(14) Замер смотрел?
16 sapphire
 
18.11.14
16:05
(0) Автор, а чё запросом-то через табличный документ низьзя никак?
17 Wobland
 
18.11.14
16:05
(15) даже не поленился
http://i.imgur.com/6wrs2yh.png
18 sapphire
 
18.11.14
16:05
(15) посмотрел и замер :)
19 H A D G E H O G s
 
18.11.14
16:05
Все время уходит на вывод в ячейку Excel.
Не используйте Excel через COM
20 sapphire
 
18.11.14
16:06
(19) Откуда ты знаешь? Может на чтение записи :)
21 Kalambur
 
18.11.14
16:08
(17) ну ты зверюга ))))
22 MM
 
18.11.14
16:08
Делаю ставку, что тормозит обращение к OLE-объектам Excel. Но и чтение из БД сделано отвратительно.
Почему бы не сделать отчёт,а потом его сохранить в Excel? Тем более что формат 2007 уже встроен в платформу и нет проблемы с 65500 строк на листе.
23 apd123
 
18.11.14
16:10
(3) И что? Надо было запросом? А смысл? Тормозит не в этом месте.

(8) Заканчивает когда заканчиваются записи. Не понял вопрос. Да и проблема явно не в этом.

(16) Попробую.

(19) А как его использовать?

Для особо умных трололо:
1) Названия полей я естественно поменял, на самом деле они называются по-другому.
2) РС таки называется "Данные". Не поверите, но бывают ситуации в которых это действительно самое подходящее и удобное название.
24 Кирпич
 
18.11.14
16:13
Вариантов много разных. Например, можно всё загнать в текст, скопировать текст в буфер обмена и вставить в Excel из буфера.
25 Kalambur
 
18.11.14
16:13
((19)(22)(23) ПолучитьМенеджерЗаписи
"Предназначен для интерактивной работы с записью регистра сведений."
26 Kalambur
 
18.11.14
16:14
(23) пиши нормальный код и все будет быстро
27 sapphire
 
18.11.14
16:14
(23) см (17)
тебе показали, где тормозит.
28 КонецЦикла
 
18.11.14
16:16
Запороцем само быстро вроде, ADOX.Catalog
29 H A D G E H O G s
 
18.11.14
16:18
(23) Используй правильно:

МассивДанных=Новый COMSafeArray("VT_VARIANT",КоличествоСтрок-1,КоличествоСтолбцов-1);
Для СчетчикСтрок=0 По КоличествоСтрок-1 Цикл
    МассивДанных.SetValue(СчетчикСтрок,0,ТекущаяСтрока.Идентификатор);
    МассивДанных.SetValue(СчетчикСтрок,1,ТекущаяСтрока.Цена);
    //и.т.д, все колонки
КонецЦикла;

ВерхняяЛеваяЯчейка= WorkBook.WorkSheets[1].Cells[НачальнаяСтрока, НачальнаяКолонка];
НижняяПраваяЯчейка= WorkBook.WorkSheets[1].Cells[НачальнаяСтрока+КоличествоСтрок-1, НачальнаяКолонка+КоличествоСтолбцов-1];
Область= WorkBook.WorkSheets[1].Range[ВерхняяЛеваяЯчейка, НижняяПраваяЯчейка];
Область.Value= МассивДанных;
30 MM
 
18.11.14
16:18
(25) Доступность: Сервер, толстый клиент, внешнее соединение.
Тонкого клиента в списке нет, странная интерактивность.

В (17) показали , что затык на Лист.Cells(х, у).Value, это минимум 3 обращения к внепроцессному COM-серверу, с маршалингом и всеми прелестями OLE.
31 H A D G E H O G s
 
18.11.14
16:19
Ну и данные, естественно - запросом, чтобы знать число строк.
32 Kalambur
 
18.11.14
16:22
(30) ну я с СП спорить точно не буду
33 apd123
 
18.11.14
18:00
(29) (31) Огромное спасибо! С использованием COMSafeArray время экспорта удалось уменьшить до 32 секунд :) http://i.imgur.com/y4Mv6FA.png

Вот какой код получился в итоге:

Процедура ПриОткрытииНаСервере()
    имяФайла = "C:\excel-export-test.xlsx";
Попытка
    Попытка
        ExcelПриложение = Новый COMОбъект("Excel.Application");
    Исключение
        Сообщить("Ошибка при запуске Microsoft Excel."
        + Символы.ПС + ОписаниеОшибки(), СтатусСообщения.Внимание);
        Возврат;
    КонецПопытки;
    Книга = ExcelПриложение.WorkBooks.Add();
    Лист = Книга.WorkSheets(1);
    
    Лист.Cells(1, 1).Value = "Заголовок 1";
//     ...
    Лист.Cells(1, 49).Value = "Заголовок 49";

    Запрос = Новый Запрос("ВЫБРАТЬ
        |    ....
        |    ИЗ РегистрСведений.Данные");
    Выборка = Запрос.Выполнить().Выбрать();
    КоличествоСтрок = Выборка.Количество();
    КоличествоСтолбцов = 50;

    МассивДанных = Новый COMSafeArray("VT_VARIANT",КоличествоСтолбцов-1, КоличествоСтрок);
    Счетчик = 0;
    Пока Выборка.Следующий() Цикл

        МассивДанных.SetValue(0, Счетчик, Выборка.Поле1);
        МассивДанных.SetValue(1, Счетчик, Выборка.Поле2);
        МассивДанных.SetValue(2, Счетчик, Выборка.Поле3);
        МассивДанных.SetValue(3, Счетчик, Выборка.Поле4);
        МассивДанных.SetValue(4, Счетчик, Выборка.Поле5);
        МассивДанных.SetValue(12, Счетчик, Выборка.Поле6);
        МассивДанных.SetValue(13, Счетчик, Выборка.Поле7);
        МассивДанных.SetValue(19, Счетчик, Выборка.Поле8);
        МассивДанных.SetValue(28, Счетчик, Выборка.Поле9);

        Счетчик = Счетчик + 1;
    КонецЦикла;
    Область = Лист.Range(Лист.Cells(2, 1), Лист.Cells(КоличествоСтрок+1, КоличествоСтолбцов-1));
    Область.Value = МассивДанных;

    ExcelПриложение.DisplayAlerts = False;
    Книга.SaveAs(имяФайла);
    ExcelПриложение.Quit();
    Сообщить("Файл выгружен успешно: " + имяФайла);
Исключение
    Сообщить("Ошибка записи данных файла :" + имяФайла);
    Сообщить(ОписаниеОшибки());
    Попытка
        ExcelПриложение.Quit();
    Исключение
    КонецПопытки;
КонецПопытки;
КонецПроцедуры