Медленная выгрузка в Excel через OLE.
Есть ли соображения из-за чего такие тормоза?
Есть набор данный TADOQuery. Задача выгрузить их в Excel. Выгружаю через OLE. Все работает без ошибок. Одна проблема - очень медленно. На выгрузку примерно 2500 записей по 10 столбцов затрачиваеться около 25 минут! Это очень много, учитывая что обычно будет обрабатываться 5-6 тыс. записей. Причем чем ближе к концу, тем больше времени затрачивается на экспорт одной записи. Если в начале выгружается в секунду ~ 6-8 записей, то потом доходит до 1 записи в секунду.
Есть ли соображения из-за чего такие тормоза?
ADO - сам по себе тормоз, это раз, а два код покажи...
ADO - сам по себе тормоз, это раз, а два код покажи...
Тормоза не в ADO, ибо сам запрос к базе выполняется за считанные секунды. Тормоза в OLE.
а два код покажи...
А код что-то вроде этого:
try
{
App=Variant::GetActiveObject("Excel.Application");
}
catch (...)
{
try
{
App=Variant::CreateObject("Excel.Application");
}
catch (...)
{
Application->MessageBox("Невозможно открыть Microsoft Excel!"
"Возможно Excel не установлен на компьютере.","Ошибка",MB_OK+MB_ICONERROR);
}
}
try
{
App.OlePropertyGet("WorkBooks").OleProcedure("Add");
Sh = App.OlePropertyGet("WorkSheets",1);
}
catch (...)
{
Application->MessageBox("Ошибка открытия книги Microsoft Excel!",
"Ошибка",MB_OK+MB_ICONERROR);
}
ADOQuery1->Open();
try
{
for (register int i = 0; i < ADOQuery1->RecordCount; i++)
{
cur = Sh.OlePropertyGet("Cells", i+1, 1);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[0]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 2);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[1]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 3);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[2]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 4);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[3]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 5);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[4]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 6);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[5]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 7);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[6]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 8);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[7]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 9);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[8]->AsString.c_str());
}
}
catch (...)
{
}
if (!App.IsEmpty()) App.OlePropertySet("Visible",true);
Sh.Clear();
App.Clear();
И именно в цикле тормоза и идут.
А код что-то вроде этого:
{
cur = Sh.OlePropertyGet("Cells", i+1, 1);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[0]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 2);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[1]->AsString.c_str());
...
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[7]->AsString.c_str());
cur = Sh.OlePropertyGet("Cells", i+1, 9);
cur.OlePropertySet("Value", ADOQuery1->Fields->Fields[8]->AsString.c_str());
}
И именно в цикле тормоза и идут.
Ясен пень, будут тормоза. Каждый раз при использовании OlePropertyGet() и OlePropertySet столько разных функций вызывается... P( Видел их объявление в заголовочных файлах? Если хочешь скорости в рантайме и не боишься трудностей, пиши через DISP-интерфейсы (делаешь в среде Import Template Library, натравливаешь на Excel.olb и вперёд...). Работать будет немного быстрее, но, чтобы всё заработало, клаву топтать придётся больше.
Извини, сейчас некогда рассказывать более подробно, но надо будет -- попытаюсь объяснить в меру своих способностей.
А код что-то вроде этого:
И именно в цикле тормоза и идут.
Ясно. Что можно сделать:
1. Вставляй записи СТРОКАМИ, а не ячейками.
2. Формируешь строки, значения в которых разделены ТАБ-ом и вставляй через буфер обмена, примерно так:
TListItem* ListItem;
String line;
TDateTime tm1, tm2;
//âñòàâèì â Excel...
XL = CreateOleObject("Excel.Application.8");
XL.OlePropertySet("Visible", CheckBox1->Checked);
v0 = XL.OlePropertyGet("Workbooks");
v0.OleProcedure("Add");
v1 = v0.OlePropertyGet("Item", 1).OlePropertyGet("Worksheets").OlePropertyGet("Item", 1);
tm1 = Time();
//ïåðâàÿ ñòðîêà - øàïêà òàáëèöû...
line = ListView1->Columns->Items[0]->Caption;
for (int i = 1; i < ListView1->Columns->Count; i++)
line = line + "\t" + ListView1->Columns->Items->Caption;
data->Add(line);
//äàëåå äîáàâëÿåì ñòðîêè â êîòîðûõ ñëîâà ðàçäåëåíû Tab-îì, Excel - ïîéìåò...
for (int j = 0; j < ListView1->Items->Count; j++) {
ListItem = ListView1->Items->Item[j];
line = ListItem->Caption;
for (int k = 0; k < ListItem->SubItems->Count; k++) {
line = line + "\t" + ListItem->SubItems->Strings[k];
}
data->Add(line);
}
//â Clipboard...
Clipboard()->AsText = data->Text;
v1.OlePropertyGet("Range", "E2:E2").OleProcedure("Select"); //íàïðèìåð íà÷èíàÿ ñ ýòîé ÿ÷åéêè...
v1.OleProcedure("Paste");
Clipboard()->Clear();
tm2 = Time();
ShowMessage("done with " + TimeToStr(tm2 - tm1));
XL.OlePropertySet("DisplayAlerts",false);
XL.OlePropertyGet("Workbooks").OlePropertyGet("Item",1).OleProcedure("SaveAs", ChangeFileExt(Application->ExeName, ".xls"));
XL.OleProcedure("Quit");
delete data;
Спасибо за советы и помощь.
Запускал из Билдера и видел тормоза. Еще раз протестировал, запустив приложение самостоятельно. В результате скорость оказалась раз в 5 выше.
Попробую предложенные способы. Возможно скорость удасться еще поднять.