Подпрограмма VBA сильно замедляется после первого выполнения

У меня есть подпрограмма, которая генерирует отчет о производительности различных портфелей в пределах 5 семейств. Дело в том, что портфели, о которых идет речь, никогда не бывают одинаковыми, как и сумма в каждой семье. Итак, я копирую и вставляю шаблон (который отформатирован и...) и добавляю отформатированную строку (содержащую формулу и...) в правильное семейство для каждого портфеля в отчете. Все работает просто отлично, код конечно не оптимален и идеален, но для того что нам нужно работает отлично. Проблема не в самом коде, а в том, что когда я выполняю код в первый раз, он выполняется очень быстро (например, 1 секунда)... но со второго раза код резко замедляется (почти 30 секунд для базового задача идентична первой). Я пробовал все расчеты вручную, не обновляя экран и ... но проблема действительно не в этом. Для меня это похоже на утечку памяти, но я не могу найти, в чем проблема! Почему код работает очень быстро, но оооочень медленнее сразу после... Какой бы ни была длина отчета и содержимое файла, мне нужно было бы закрыть Excel и снова открыть его для каждого отчета.

** Не уверен, что я понимаю, но это не потому, что код делает файл excel больше или что-то в этом роде, потому что после первого (быстрого) выполнения, если я сохраню книгу, закрою и снова открою ее, (новое) первое выполнение снова будет очень быстро, но если бы я сделал то же самое, не закрывая и не открывая снова, это было бы очень медленно...^!^!

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

Конец сабвуфера


person user3666381    schedule 22.05.2014    source источник


Ответы (3)


В данный момент у меня нет с собой ноутбука, но вы можете попробовать несколько вещей:

  1. используйте явный параметр, чтобы убедиться, что вы объявили все переменные перед их использованием;
  2. насколько я помню, собственный тип vba для чисел не integer, а long, и целые числа преобразуются в long, чтобы сэкономить время вычислений, используя long вместо целых чисел;
  3. ваши семейные переменные определены как строки, но вы храните в них целые ячейки, а не их значения, т.е. =cells() вместо =cells().value;
  4. эмпирическое правило состоит в том, чтобы использовать cells(rows.count, 4).end(xlup).row вместо cells(3, 4).end(xldown).row.;
  5. условное форматирование может сильно замедлить работу;
  6. по возможности используйте цикл for each для диапазона вместо while или даже скопируйте диапазон в массив вариантов и повторите его (это самое быстрое решение);
  7. использовать раннее связывание вместо позднего связывания, т. е. определять объекты в правильном типе как можно скорее;
  8. не показывать область печати (разрывы страниц и т.п.);
  9. попробуйте профилировать и найти узкие места - см. поиск узких мест в excel vba;
  10. вставляйте только значения, если вам не нужны форматы;
  11. очищать буфер обмена после каждого копирования/вставки;
  12. установите для объектов значение Ничего после завершения их использования;
  13. используйте Value2 вместо Value — это будет игнорировать форматирование и принимать только числовое значение вместо форматированного значения;
  14. использовать объекты листа и ссылаться на них, например

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

а затем везде использовать sh_raw вместо Sheets("RawDataMV");

person MPękalski    schedule 24.05.2014
comment
Спасибо за вашу помощь.... 1) опция явно включена, 2) спасибо за это, полезно знать 3) еще раз спасибо 4) еще одна полезная вещь! Но все равно ничего не меняется... Знаете ли вы какой-нибудь способ RESTART памяти Excel, как если бы мы снова открыли книгу? Потому что я действительно не понимаю, что даже если я запускаю те же самые начальные ситуации, снова второй раз займет в 100 раз больше времени... - person user3666381; 27.05.2014
comment
Невозможно перезапустить память Excel. VBA не C, и вы не можете повлиять на объем памяти Excel. Обычно Excel использует определенный объем памяти, а затем остается там. Чтобы сделать его как можно меньше, просто установите значение Nothing для всех больших объектов, которые вы не используете. - person MPękalski; 27.05.2014

У меня была такая же проблема, но я, наконец, понял это. Это прозвучит нелепо, но все это связано с настройкой страницы для печати. По-видимому, Excel пересчитывает его каждый раз, когда вы обновляете ячейку, и это вызывает замедление.

Попробуйте использовать

Sheets("Rapport").DisplayPageBreaks = False

в начале вашей рутины, перед любыми расчетами и

Sheets("Rapport").DisplayPageBreaks = True

в конце этого.

person szaleski    schedule 12.09.2016

У меня такая же проблема. Я далек от профессионального программиста. Приведенные выше ответы помогли моей программе, но не решили проблему. Я запускаю Excel 2013 на 5-летнем ноутбуке. Откройте программу, не запуская ее, перейдите в меню «Файл»> «Параметры дополнительно», прокрутите вниз до раздела «Данные» и снимите флажок «Отключить отмену для обновления большой сводной таблицы…» и «Отключить отмену для операции с моделью больших данных». Вы также можете попробовать оставить их отмеченными, но уменьшить их значение. Один или оба из них, похоже, создают постоянно увеличивающийся файл, который замедляет макрос и, в конечном итоге, останавливает его. Я предполагаю, что закрытие Excel очищает файлы, которые они создают, поэтому он работает быстро, когда Excel закрывается и снова открывается, по крайней мере, на некоторое время. Кто-то с большим знанием должен будет объяснить, что будут делать эти изменения и каковы последствия их отмены. Похоже, эти изменения будут применены ко всем новым создаваемым вами электронным таблицам. Возможно, в этих изменениях не было бы необходимости, если бы у меня был более новый, более мощный компьютер.

person Aero    schedule 14.03.2016