Имя: Пароль:
1C
 
Как ускорить выгрузку в эксель?
,
0 zzerro
 
25.01.11
17:24
Тема конечно забитая, но никак не могу увеличить скорость записи в эксель большого объема данных (около 100 тыс строк).
Пробовал через ТабличныйДокумент.Записать(), но насколько я понял 8.1 не может записывать в xlsx, а в формате xls не входит по количесву строк.
Пробовал через Новый COMОбъект("Excel.Application"), но заполнение файла через Лист.Cells(НомерСтроки, 1).Value = Значение;  работает ужасно медленно, хоть и снимается ограничение по количесву строк, т.к. установлен 2010 офис.

Подскажите, чем еще можно записать данные в эксель, желательно с примером.
1 izekia
 
25.01.11
17:26
можно записать в хмл таблицу с хслт форматированием
минус - не поддерживаются группировки
2 Nexux
 
25.01.11
17:26
через ADO, возможно
3 skunk
 
25.01.11
17:28
2010 само по себе было "снятно" ограничение на количество строк ... хотя по факту ограничение есть
4 izekia
 
25.01.11
17:28
(2) получается апдейтить каждую строчку, не медленно получится?
5 skunk
 
25.01.11
17:29
хотя данное ограничение еще 2007 снялось
6 skunk
 
25.01.11
17:30
(4)нет не получается ... ну можно ускорить работу самого екселя и по оле ... правда не так сильно как с адо ...
7 mikecool
 
25.01.11
17:30
(0) присвоение не тормозит обычно, оформляешь наверное тут же при выводе?
8 mikecool
 
25.01.11
17:31
+7 рисовал как то вывод в эксель из 7-ки 8-10 листов по 30-40 тыщ записей
сам вывод - занимал минуты 2-3
оформление - уже массово после вывода
9 skunk
 
25.01.11
17:32
надо отключать в екселе видимость ... перерисовку экрана ...
10 mikecool
 
25.01.11
17:36
(9) кстати да, важный момент
а насчет оформления после вывода - замерял, производительность вырастает в 10-20 раз
11 zzerro
 
25.01.11
17:39
(7) Мне оформление не нужно, ничего такого не делаю, просто присваиваю значения ячейкам.
(9) Отключал, никакой разницы ощутимой не заметил

Вот собственно код:

Эксель = Новый COMОбъект("Excel.Application");
// Запретим экселю выдавать всякие предупреждения
Эксель.DisplayAlerts = False;
   
// Для ускорения вывода информации в Excel можно отключить обновление экрана.
Эксель.ScreenUpdating = 0;
Эксель.EnableEvents = 0;
Эксель.Visible = 0;

Книга = Эксель.WorkBooks.Add();
Лист = Книга.WorkSheets(1);

// Рез - это таблица значений, которую нужно сохранить в эксель
КолЗап = Рез.Количество();
НомерСтроки = 1;
Для каждого Стр из Рез Цикл
   ПроцентВыполнения = Цел(НомерСтроки/КолЗап*100);
   Если ПроцентВыполнения % 5 = 0 Тогда
       // Обновляем состояние каждые 5 % элементов
       Состояние("Построение отчета: " + ПроцентВыполнения + " %");
   КонецЕсли;
   НомерСтроки = НомерСтроки + 1;
   Лист.Cells(НомерСтроки, 1).Value = Стр.Орг;  
   // Дата, номер, сумма счета
   Лист.Cells(НомерСтроки, 2).Value = Формат(Стр.Счет_Дата,"ДФ=dd.MM.yyyy");
   Лист.Cells(НомерСтроки, 3).Value = Формат(Стр.Счет_Номер,"ЧГ=0");
   Лист.Cells(НомерСтроки, 4).Value = Стр.Счет_Сумма;
// и так далее еще 15 колонок
12 zzerro
 
25.01.11
17:40
80 тыс записей выводит минут 30 а то и больше... многовато
13 Happy Bear
 
25.01.11
17:41
(11) через ADO скорость увеличивается существенно, сам проверял
14 zzerro
 
25.01.11
17:41
(1) А можно пример?
15 simol
 
25.01.11
17:42
В DBF, а его открыть в Excel?
16 zzerro
 
25.01.11
17:42
(13) Можно пример, а то считывание через ADO делал, а вот с записью не сталкивался еще
17 zzerro
 
25.01.11
17:43
(15) DBF не подойдет... уж лучше тогда csv
18 КМ155
 
25.01.11
17:47
(16) тот же рекордсет
+ AddNew
19 izekia
 
25.01.11
17:54
(14) попробую накидать, ты, кстати, зачем дату форматируешь?
20 izekia
 
25.01.11
17:55
кстати, еще есть вариант напрямую в эксель тащить с сиквела, но здесь проблема с безопасностью, как я понимаю
21 Happy Bear
 
25.01.11
17:57
(16)

СтрокаПодключения = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source = " + ИмяФайлаЗагрузки;
СтрокаПодключения = СтрокаПодключения + "; Extended Properties = "+"""Excel 8.0"+";HDR=NO;IMEX=0"";";

Command = Новый COMОбъект("ADODB.Command");
axCatalog = Новый COMОбъект("ADOX.Catalog");                                           axCatalog.ActiveConnection = Connection;
ИмяТаблицы = axCatalog.Tables(0).Name;
RecordSet = Новый COMОбъект("ADODB.RecordSet");
Command.ActiveConnection = Connection;
Command.CommandText = "CREATE TABLE Выгрузка (N float, Артикул char(50), Наименование char(255), Количество float, СтавкаНДС char(25), Цена float, СуммаНДС float, СуммаСНДС float, ГодКампании float, СимволКампании float, ВидТовара float)";
Command.CommandType = 1;
RecordSet = Command.Execute();

           Command.CommandText = "INSERT INTO Выгрузка VALUES (" + Формат(ВыборкаПоСтрокам.НомерСтроки, СтрокаФормата) + ", '" + Артикул + "', '" + Наименование + "', " + Формат(ВыборкаПоСтрокам.Количество, СтрокаФормата) + ", '" + ВыборкаПоСтрокам.СтавкаНДС + "', " + Формат(ВыборкаПоСтрокам.Цена, СтрокаФормата) + ", " + Формат(ВыборкаПоСтрокам.СуммаНДС, СтрокаФормата) + ", " + Формат(ВыборкаПоСтрокам.СуммаСНДС, СтрокаФормата) + ", " + Формат(ВыборкаПоСтрокам.ГодКампании, СтрокаФормата) + ", " + Формат(ВыборкаПоСтрокам.СимволКампании, СтрокаФормата) + ", " + Формат(ВыборкаПоСтрокам.ВидТовара, СтрокаФормата) + ")";
Command.CommandType = 1;
RecordSet = Command.Execute();
22 Tatitutu
 
25.01.11
17:59
сохрани таблицу как копию в формате htm
а потом открой в ексели и сохрани как нужно
в разы скорость изменится.
23 izekia
 
25.01.11
18:06
в общем логика такая, самому пока некогда:
http://blogs.msdn.com/b/brian_jones/archive/2005/06/30/434473.aspx
24 izekia
 
25.01.11
18:12
просто дома все ссылки
25 ado
 
25.01.11
18:13
(0) А как насчет Йокселя? Или он с новыми форматами офиса не дружит?
26 AversDik2
 
25.01.11
18:13
(0) Выгрузить в SQL (отдельную базу) и из нее взять данные в Excel
27 ado
 
25.01.11
18:15
(26) По идее, не быстрее ADO будет.
28 asady
 
26.01.11
08:56
29 izekia
 
26.01.11
15:50
через COMSafeArray конечно быстрее
вот простой пример с использованием XML и XSL:
   тз = Новый ТаблицаЗначений;
   тз.Колонки.Добавить("Число", Новый ОписаниеТипов("Число"), "Число", 10);
   тз.Колонки.Добавить("Строка", Новый ОписаниеТипов("Строка"), "Строка", 30);
   тз.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"), "Дата", 10);
   Для инд = 1 По 10 Цикл
       стр = тз.Добавить();
       стр.Число = инд;
       стр.Строка = "Строка";
       стр.Дата = ТекущаяДата();
   КонецЦикла;
   записьXML = Новый ЗаписьXML;
   записьXML.УстановитьСтроку("windows-1251");
   записьXML.ЗаписатьОбъявлениеXML();
   записьXML.ЗаписатьНачалоЭлемента("ТаблицаЗначений");
   записьXML.ЗаписатьНачалоЭлемента("Колонки");
   Для Каждого колонка из тз.Колонки Цикл
       записьXML.ЗаписатьНачалоЭлемента("Колонка");
       записьXML.ЗаписатьАтрибут("Заголовок", колонка.Заголовок);
       записьXML.ЗаписатьАтрибут("Ширина", Строка(колонка.Ширина));
       записьXML.ЗаписатьКонецЭлемента();
   КонецЦикла;
   записьXML.ЗаписатьКонецЭлемента();
   Для Каждого строка из тз Цикл
       записьXML.ЗаписатьНачалоЭлемента("Строка");
       Для Каждого колонка из тз.Колонки Цикл
           записьXML.ЗаписатьНачалоЭлемента(колонка.Имя);
           записьXML.ЗаписатьТекст(XMLСтрока(строка[колонка.Имя]));
           записьXML.ЗаписатьКонецЭлемента();
       КонецЦикла;
       записьXML.ЗаписатьКонецЭлемента();
   КонецЦикла;
   записьXML.ЗаписатьКонецЭлемента();
   хсл = Новый ПреобразованиеXSL;
   хсл.ЗагрузитьИзСтроки(  "<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"" xmlns:ss=""urn:schemas-microsoft-com:office:spreadsheet"">
                           |
                           |    <xsl:template match=""/"">
                           |        <ss:Workbook>
                           |            <ss:Styles>
                           |                <ss:Style ss:ID=""1"">
                           |                    <ss:Font ss:Bold=""1""/>
                           |                </ss:Style>
                           |            </ss:Styles>
                           |            <ss:Worksheet ss:Name=""Test"">
                           |                <ss:Table>
                           |                    <xsl:apply-templates />
                           |                </ss:Table>
                           |            </ss:Worksheet>
                           |        </ss:Workbook>
                           |    </xsl:template>
                           |
                           |    <xsl:template match=""ТаблицаЗначений/Колонки"">
                           |        <ss:Row ss:StyleID=""1"">
                           |            <xsl:for-each select=""Колонка"">
                           |                <ss:Cell>
                           |                    <ss:Data ss:Type=""String""><xsl:value-of select=""@Заголовок""/></ss:Data>
                           |                </ss:Cell>
                           |            </xsl:for-each>
                           |        </ss:Row>
                           |        <xsl:apply-templates />
                           |    </xsl:template>
                           |
                           |    <xsl:template match=""ТаблицаЗначений/Строка"">
                           |        <ss:Row>
                           |            <xsl:for-each select=""*"">
                           |                <ss:Cell>
                           |                    <ss:Data ss:Type=""String"">
                           |                        <xsl:value-of select=""."" />
                           |                    </ss:Data>
                           |                </ss:Cell>
                           |            </xsl:for-each>
                           |        </ss:Row>
                           |    </xsl:template>
                           |
                           |</xsl:stylesheet>");
   результат = Новый ЗаписьXML;
   результат.ОткрытьФайл("c:\work\temp\test.xls");
   хсл.ПреобразоватьИзСтроки(записьXML.Закрыть(), результат);
   результат.Закрыть();
Кaк может человек ожидaть, что его мольбaм о снисхождении ответит тот, кто превыше, когдa сaм он откaзывaет в милосердии тем, кто ниже его? Петр Трубецкой