views:

906

answers:

5

We have a lot of reports that are generated via VBA & Excel. Only a small percentage of the reports are actual calculations - the majority of the work is sql calls and formatting/writing of cells. The longest of which takes several hours, the majority takes around 20-30 mins each.

The VBA/Excel code plugs into a dll that the VB6 desktop apps use - it's here that all the sql calls are made. While I am sure that there is room for improvement here, it's not this that concerns me - the desktop apps are fairly snappy.

Two VBA functions are used in abundance: These are called GetRange and SetupCell and they nearly always appear together. The GetRange function is a wrapper for the Excel.Range object. It takes a sheet, and 4 values for the extents of the range. Its main use is to pick the cell for editing. There doesn't appear to be much chance of optmising it, but is it the best way?

Its partner is SetupCell. This takes a Excel.Range object, text and a dozen parameters about the cell (font, borders, etc). Most of these parameters are optional booleans but again, it seems very wasteful. Some of these can be set posthumously but some are dependant on the values contained in the cell.

There's quite a lot of code contained in these functions, mainly if statements and work won't appreciate me posting it.

I guess I've got two questions: Is there a better way and what is it and is there are free profiler that I can use to see if the bulk of the time is here or in the dll?

+1  A: 

Have you thought about using an actual reporting solution? What's your backend db? If you are using MSSQL 2000 or higher there is a fairly decent reporting solution you can use free of charge. SQL Server Reporting Services.

It sounds as if the reports are spending most of their time formatting cells. This could be why the reports seem so slow and the desktop app doesn't.

Alternatively, if you know the formatting before hand and it is fairly static, you could pre-format the sheets to cut down on some of the work.

I will throw this in there as well. Most reporting solutions will allow for conditional formatting and such, but since they are designed to work as such performance will be much better than having Excel do it.

toast
Not that easy. Reports need to be of different lengths, some of the cells need to be coloured depending on the value in cells (or a sum of the cells).
graham.reeds
+1  A: 

This isn't a profiler recommendation, but it is a suggestion for speeding up Excel macros that are spending their time updating the screen. I've had excellent results by turning off screen updating while the macro is running: set Application.ScreenUpdating= False, and also using a number of other similar settings. Just be sure to turn them back on again when the macro finishes :P

MarkJ
We already do this and we set Application.Calculation to manual (xlCalculationManual).
graham.reeds
A: 

It's not free but you can profile with this. I suspect the demo will be adequate to your needs: http://www.aivosto.com/vbwatch.html

Oorang
For some of the reports, yes. For others, no. For each worksheet we have a vba 'file', plus several support 'files'. It definately won't work on the dll as it has over 100 hundred classes and modules.
graham.reeds
+4  A: 

several hours is ridiculous for a report.

If the problem is VBA buy "Professional Excel Development" (stephen Bullen, Rob Bovey et al): this has a free VBA profiler called PerfMon.

If the problem is Excel Calculation see http://msdn.microsoft.com/en-us/library/aa730921.aspx?ppud=4

But I would guess that the problem is the high overhead associated with referencing things cell-by-cell: you should always work in large blocks of cells at a time.

Charles Williams
Nice pimpage for yourself:-) Seriously though the problem is not with calculation - we do very little calculation (excel or otherwise). A profiler would help determine if either the calls to the db is killing the system or the slow cell-by-cell formatting is killing it. How can you work with a large block of cells at a time?
graham.reeds
If you don't want to use Stephen Bullen's PerfMon then why not just add some timeing code using the high-res windows timer?doing things in blocks: the basic approach is to assign a range to a variant variable:Dim vArr as variantvArr=Range("B4:z456").value2this will give you a variant containing a 2-d arrayYou can manipulate the array and send it back to excelRange("B4:z456")=vArrsimilarly when formatting cells format a range of cells (probably using copy/pastespecial from a template sheet) rather than a single cell.etc. etc.
Charles Williams
A: 

It sounds like the VBA code (or the VB code thats writing to the sheets) is doing so line by line, this can take ages, and is crap design, normally done by people who don't know the excel OM, or if the code was used in XL97. Write to excel as a variant in one go. Formate the sheet after the data is all imported. Thanks Ross

Ross