excelperformancevbamemory-leaksslowdown

VBA subroutine slows down a lot after first execution


I have a subroutine that generates a report of performance of different portfolios within 5 families. The thing is that the portfolios in question are never the same and the amount in each family neither. So, I copy paste a template (that is formated and...) and add the formated row (containing the formula and...) in the right family for each portfolio in the report. Everything works just fine, the code is not optimal and perfect of course, but it works fine for what we need. The problem is not the code itself, it is that when I execute the code the first time, it goes really fast (like 1 second)... but from the second time, the code slows down dramatically (almost 30 second for a basic task identical to the first one). I tried all the manual calculation, not refreshing the screen and ... but it is really not where the problem comes from. It looks like a memory leak to me, but I cannot find where is the problem! Why would the code runs very fast but sooooo much slower right after... Whatever the length of the report and the content of the file, I would need to close excel and reopen it for each report.

**Not sure if I am clear, but it is not because the code makes the excel file larger or something, because after the first (fast) execution, if I save the workbook, close and reopen it, the (new) first execution will again be very fast, but if I would have done the same excat thing without closing and reopening it would have been very slow...^!^!

Dim Family As String
Dim FamilyN As String
Dim FamilyP As String
Dim NumberOfFamily As Integer
Dim i As Integer
Dim zone As Integer


Sheets("RapportTemplate").Cells.Copy Destination:=Sheets("Rapport").Cells
Sheets("Rapport").Activate

i = 3
NumberOfFamily = 0
FamilyP = Sheets("RawDataMV").Cells(i, 4)
While (Sheets("RawDataMV").Cells(i, 3) <> "") And (i < 100)

    Family = Sheets("RawDataMV").Cells(i, 4)
    FamilyN = Sheets("RawDataMV").Cells(i + 1, 4)

    If (Sheets("RawDataMV").Cells(i, 3) <> "TOTAL") And _
    (Sheets("RawDataMV").Cells(i, 2) <> "Total") Then

        If (Family <> FamilyP) Then
            NumberOfFamily = NumberOfFamily + 1
        End If
        With Sheets("Rapport")
            .Rows(i + 8 + (NumberOfFamily * 3)).EntireRow.Insert
            .Rows(1).Copy Destination:=Sheets("Rapport").Rows(i + 8 + (NumberOfFamily * 3))
            .Cells(i + 8 + (NumberOfFamily * 3), 6).Value = Sheets("RawDataMV").Cells(i, 2).Value
            .Cells(i + 8 + (NumberOfFamily * 3), 7).Value = Sheets("RawDataMV").Cells(i, 3).Value
        End With
    End If
    i = i + 1
    FamilyP = Family
Wend

For i = 2 To 10
    If Sheets("Controle").Cells(16, i).Value = "" Then
        Sheets("Rapport").Cells(1, i + 11).EntireColumn.Hidden = True
    Else
        Sheets("Rapport").Cells(1, i + 11).EntireColumn.Hidden = False
    End If
Next i
Sheets("Rapport").Cells(1, 1).EntireRow.Hidden = True

'Define printing area
zone = Sheets("Rapport").Cells(4, 3).End(xlDown).Row
Sheets("Rapport").PageSetup.PrintArea = "$D$4:$Y$" & zone


Sheets("Rapport").Calculate
Sheets("RANK").Calculate
Sheets("SommaireGroupeMV").Calculate
Sheets("SommaireGroupeAlpha").Calculate
Application.CutCopyMode = False

End Sub


Solution

  • I do not have laptop with me at the moment but you may try several things:

    1. use option explicit to make sure you declare all variables before using them;
    2. from what I remember native vba type for numbers is not integer but long, and integers are converted to long, to save the computation time use long instead of integers;
    3. your Family variables are defined as strings but you store in them whole cells and not their values i.e. =cells() instead of =cells().value;
    4. a rule of a thumb is to use cells(rows.count, 4).end(xlup).row instead of cells(3, 4).end(xldown).row.;
    5. conditional formatting may slow down things a lot;
    6. use for each loop on a range if possible instead of while, or even copy range to variant array and iterate over that (that is the fastest solution);
    7. use early binding rahter of late binding, i.e., define objects in a proper type as soon a possible;
    8. do not show printing area (page breaks etc.);
    9. try to do some pofiling and look for the bottlenecks - see finding excel vba bottlenecks;
    10. paste only values if you do not need formats;
    11. clear clipboard after each copy/paste;
    12. set objects to Nothing after finishing using them;
    13. use Value2 instead of Value - that will ignore formatting and take only numeric value instead of formatted value;
    14. use sheet objects and refer to them, for example

      Dim sh_raw As Sheet, sh_rap As Sheet set sh_raw = Sheets("RawDataMV") set sh_rap = Sheets("Rapport")

    and then use sh_raw instead of Sheets("RawDataMV") everywhere;