Тъй като вашите макроси в Excel стават все по-стабилни и сложни, може да откриете, че губят производителност. Когато обсъждаме макроси, думата производителност обикновено е синоним на скорост . Скоростта е колко бързо вашите VBA процедури изпълняват предвидените задачи. Следват десет начина да поддържате вашите макроси в Excel да работят на оптималното им ниво на производителност.
Спиране на изчисленията на листа
Знаете ли, че всеки път, когато клетка, която засяга формула във вашата електронна таблица, бъде променена или манипулирана, Excel преизчислява целия работен лист? В работни листове, които имат голямо количество формули, това поведение може драстично да забави вашите макроси.
Можете да използвате свойството Application.Calculation, за да кажете на Excel да премине към режим на ръчно изчисление. Когато работната книга е в режим на ръчно изчисление, тя няма да се преизчисли, докато не задействате изрично изчисление чрез натискане на клавиша F9.
Поставете Excel в режим на ръчно изчисление, стартирайте кода си и след това превключете обратно към режим на автоматично изчисление.
Подмакрос1()
Application.Calculation = xlCalculationManual
„Поставете своя макрокод тук
Application.Calculation = xlCalculationAutomatic
Край под
Задаването на режима на изчисление обратно на xlCalculationAutomatic автоматично ще задейства преизчисляване на работния лист, така че няма нужда да натискате клавиша F9, след като вашият макрос се изпълни.
Деактивиране на актуализирането на екрана на листа
Може да забележите, че когато вашите макроси се изпълняват, екранът ви трепти доста. Това трептене е Excel, който се опитва да преначертае екрана, за да покаже текущото състояние на работния лист. За съжаление всеки път, когато Excel преначертава екрана, той заема ресурси от паметта.
Можете да използвате свойството Application.ScreenUpdating, за да деактивирате актуализациите на екрана, докато вашият макрос не завърши. Деактивирането на актуализирането на екрана спестява време и ресурси, позволявайки на вашия макрос да работи малко по-бързо. След като вашият макрокод приключи, можете да включите отново актуализирането на екрана.
Подмакрос1()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
„Поставете своя макрокод тук
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = Вярно
Край под
След като зададете свойството ScreenUpdating обратно на True, Excel автоматично ще задейства преначертаване на екрана.
Изключване на актуализациите в лентата на състоянието
Лентата на състоянието на Excel, която се показва в долната част на прозореца на Excel, обикновено показва напредъка на определени действия в Excel. Ако вашият макрос работи с много данни, лентата на състоянието ще заеме някои ресурси.
Важно е да се отбележи, че изключването на актуализирането на екрана е отделно от изключване на дисплея на лентата на състоянието. Лентата на състоянието ще продължи да се актуализира, дори ако деактивирате актуализирането на екрана. Можете да използвате свойството Application.DisplayStatusBar, за да деактивирате временно всякакви актуализации на лентата на състоянието, като допълнително подобрите производителността на вашия макрос:
Подмакрос1()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
„Поставете своя макрокод тук
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = Вярно
Application.DisplayStatusBar = Вярно
Край под
Указване на Excel да игнорира събития
Можете да внедрите макроси като процедури за събития, като казвате на Excel да стартира определен код, когато работен лист или работна книга се промени.
Понякога стандартните макроси правят промени, които ще задействат процедура за събитие. Например, ако имате стандартен макрос, който манипулира няколко клетки на Sheet1, всеки път, когато клетка на този лист се промени, вашият макрос трябва да спре, докато се изпълнява събитието Worksheet_Change.
Можете да добавите друго ниво на повишаване на производителността, като използвате свойството EnableEvents, за да кажете на Excel да игнорира събития, докато вашият макрос се изпълнява.
Задайте свойството EnableEvents на False, преди да стартирате вашия макрос. След като вашият макрокод приключи, можете да зададете свойството EnableEvents обратно на True.
Подмакрос1()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
„Поставете своя макрокод тук
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = Вярно
Application.DisplayStatusBar = Вярно
Application.EnableEvents = Вярно
Край под
Скриване на прекъсвания на страници
Всеки път, когато вашият макрос променя броя на редовете, променя броя на колоните или променя настройката на страницата на работен лист, Excel е принуден да отдели време за преизчисляване на прекъсванията на страниците, показани на листа.
Можете да избегнете това поведение, като просто скриете прекъсванията на страниците, преди да стартирате своя макрос.
Задайте свойството на листа DisplayPageBreaks на False, за да скриете прекъсванията на страници. Ако искате да продължите да показвате прекъсвания на страници след изпълнение на вашия макрос, задайте свойството на листа DisplayPageBreaks обратно на True.
Подмакрос1()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
Activesheet.DisplayPageBreaks = False
„Поставете своя макрокод тук
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = Вярно
Application.DisplayStatusBar = Вярно
Application.EnableEvents = Вярно
Activesheet.DisplayPageBreaks = Вярно
Край под
Спиране на актуализациите на централната таблица
Ако вашият макрос манипулира обобщени таблици, които съдържат големи източници на данни, може да изпитате лоша производителност, когато правите неща като динамично добавяне или преместване на централни полета.
Можете да подобрите производителността на вашия макрос, като преустановите преизчисляването на обобщената таблица, докато не бъдат направени всички промени в централното поле. Просто задайте свойството PivotTable.ManualUpdate на True, за да отложите преизчисляването, изпълнете своя макрокод и след това задайте свойството PivotTable.ManualUpdate обратно на False, за да задействате преизчисляването.
Подмакрос1()
ActiveSheet.PivotTables("PivotTable1").ManualUpdate=Вярно
„Поставете своя макрокод тук
ActiveSheet.PivotTables("PivotTable1").ManualUpdate=False
Край под
Избягване на копиране и поставяне
Важно е да запомните, че въпреки че Macro Recorder спестява време, като пише VBA код вместо вас, той не винаги пише най-ефективния код. Отличен пример е как Macro Recorder улавя всяко действие за копиране и поставяне, което извършвате по време на запис.
Можете да дадете лек тласък на макросите си, като изрежете посредника и извършите директно копиране от една клетка в клетка дестинация. Този алтернативен код използва аргумента Destination, за да заобиколи клипборда и да копира съдържанието на клетка A1 директно в клетка B1.
Диапазон("A1"). Дестинация на копиране:=Обхват("B1")
Ако трябва да копирате само стойности (не форматиране или формули), можете да подобрите производителността още повече, като избягвате метода за копиране заедно. Просто задайте стойността на целевата клетка на същата стойност, намерена в клетката източник. Този метод е около 25 пъти по-бърз от използването на метода за копиране:
Диапазон("B1").Стойност = Диапазон("A1").Стойност
Ако трябва да копирате само формули от една клетка в друга (не стойности или форматиране), можете да зададете формулата на целевата клетка на същата формула, съдържаща се в изходната клетка:
Диапазон("B1").Формула = Диапазон("A1").Формула
Използване на израза With
Когато записвате макроси, често ще манипулирате един и същ обект повече от веднъж. Можете да спестите време и да подобрите производителността, като използвате израза With, за да извършите няколко действия върху даден обект с един кадър.
Инструкцията With, използвана в следния пример, казва на Excel да приложи всички промени във форматирането наведнъж:
С диапазон("A1").Шрифт
.Удебелен = Вярно
.Курсив = Вярно
.Подчертаване = xlUnderlineStyleSingle
Край с
Създаването на навика да разделяте действията в изразите With не само ще поддържате вашите макроси да работят по-бързо, но и ще улесни четенето на вашия макрокод.
Избягване на метода Select
Macro Recorder обича да използва метода Select за изрично избиране на обекти, преди да предприеме действия върху тях. По принцип не е необходимо да избирате обекти, преди да работите с тях. Всъщност можете драстично да подобрите производителността на макросите, като не използвате метода Select.
След като запишете вашите макроси, направете си навик да променяте генерирания код, за да премахнете методите Select. В този случай оптимизираният код ще изглежда по следния начин:
Sheets("Sheet1").Обхват("A1").FormulaR1C1 = "1000"
Sheets("Sheet2").Обхват("A1").FormulaR1C1 = "1000"
Sheets("Sheet3").Обхват("A1").FormulaR1C1 = "1000"
Имайте предвид, че нищо не се избира. Кодът просто използва йерархията на обектите, за да приложи необходимите действия.
Ограничаване на пътуванията до работния лист
Друг начин да ускорите вашите макроси е да ограничите броя на препратките към данни от работния лист във вашия код. Винаги е по-малко ефективно да се вземат данни от работния лист, отколкото от паметта. Това означава, че вашите макроси ще работят много по-бързо, ако не им се налага многократно да взаимодействат с работния лист.
Например, следният прост код принуждава VBA непрекъснато да се връща към Sheets(“Sheet1”).Range(“A1”), за да получи номера, необходим за сравнението, което се извършва в оператора If:
За Месец на отчета = 1 до 12
Ако Range("A1").Стойност = ReportMonth Тогава
MsgBox 1000000 / Месец на отчета
Край, ако
Следващ отчет месец
Много по-ефективен метод е да запишете стойността в Sheets(“Sheet1”).Range(“A1”) в променлива, наречена MyMonth. По този начин кодът препраща към променливата MyMonth вместо към работния лист:
Dim MyMonth като цяло число
MyMonth = Диапазон ("A1"). Стойност
За Месец на отчета = 1 до 12
Ако MyMonth = ReportMonth Тогава
MsgBox 1000000 / Месец на отчета
Край, ако
Следващ отчет месец
Помислете за използването на променливи за работа с данни в паметта, за разлика от директното препращане към работни листове.
Избягвайте прекомерните препратки
Когато извиквате метод или свойство на обект, той трябва да премине през интерфейса IDispatch на OLE компонента. Извикванията към тези OLE компоненти отнемат време, така че намаляването на броя на препратките към OLE компоненти може да подобри скоростта на макро кода.
За извикване на свойства или методи на обекти обикновено се използва методът за представяне на Object.Method , т.е. символ се използва за извикване на свойства и методи.
Следователно броят на извикванията на метод или свойство може да се прецени според броя на символите ".". Колкото по-малко е "." символ, толкова по-бързо се изпълнява кодът.
Например следният израз включва 3 символа ".".
ThisWorkbook.Sheet1.Range("A1").Value = 100
Следното твърдение има само един символ ".".
Activewindow.Top = 100
Ето няколко трика за намаляване на броя на символите "." да тичам по-бързо.
Първо, когато трябва да се обърнете към един и същ обект многократно, можете да зададете обекта на променлива, за да намалите броя на извикванията. Например, следният код изисква две повиквания на ред.
ThisWorkbook.Sheets("Sheet1").Cells(1, 1) = 100
ThisWorkbook.Sheets("Sheet1").Cells(2, 1) = 200
ThisWorkbook.Sheets("Sheet1").Cells(3, 1) = 300
Тъй като обектът Sheets("Sheet1") трябва да бъде препратен многократно, той може първо да бъде зададен на променлива sht , така че всеки код трябва да бъде извикан само веднъж.
Set sht = ThisWorkbook.Sheets("Sheet1")
sht.Cells(1, 1) = 100
sht.Cells(2, 1) = 200
sht.Cells(3, 1) = 300
Второ, ако не искате да декларирате временна променлива sht, можете също да използвате израза With , споменат по-рано. Както е показано в следния пример:
With ThisWorkbook.Sheets("Sheet1")
.Cells(1, 1) = 100
.Cells(2, 1) = 200
.Cells(3, 1) = 300
End With
Трето, когато има много цикли, опитайте се да запазите свойствата и методите извън цикъла. Когато използвате повторно стойност на свойството на същия обект в цикъл, можете първо да присвоите стойността на свойството на определена променлива извън цикъла и след това да използвате променливата в цикъла, което може да постигне по-висока скорост. Както е показано в следния пример:
For i = 1 To 1000
ThisWorkbook.Sheets("Sheet1").Cells(1, 1) = Cells(1, 2).Value
ThisWorkbook.Sheets("Sheet1").Cells(2, 1) = Cells(1, 2).Value
ThisWorkbook.Sheets("Sheet1").Cells(3, 1) = Cells(1, 2).Value
Next i
Всеки цикъл в този пример получава свойството Value на клетката Cells(1,2). Ако присвоите свойството Value на Cells(1.2) на променлива преди началото на цикъла, ще получите по-бързо изпълнение. Както е показано в следния пример:
tmp = Cells(1, 2).Value
For i = 1 To 1000
ThisWorkbook.Sheets("Sheet1").Cells(1, 1) = tmp
ThisWorkbook.Sheets("Sheet1").Cells(2, 1) = tmp
ThisWorkbook.Sheets("Sheet1").Cells(3, 1) = tmp
Next i
Горният код извиква ThisWorkbook.Sheets("Sheet1") всеки път, когато зацикли. Можете да направите това по-бързо, като използвате израза With , за да преместите извикването към ThisWorkbook.Sheets("Sheet1") извън цикъла. Както е показано в следния пример:
tmp = Cells(1, 2).Value
With ThisWorkbook.Sheets("Sheet1")
For i = 1 To 1000
.Cells(1, 1) = tmp
.Cells(2, 1) = tmp
.Cells(3, 1) = tmp
Next i
End With
Избягвайте използването на типове варианти
Начинаещите обикновено предпочитат да използват променливи тип Variant, което има предимството да е по-малко сложно, тъй като всеки тип данни може да се използва без проблем с препълване на паметта, ако данните са твърде големи за типовете данни Integer или Long. Данните от тип Varienmt обаче изискват повече допълнително пространство в паметта, отколкото другите определени типове (2 байта за данни Integer, 4 байта за данни Long и 16 байта за данни Variant), VBA изисква повече време за обработка на данни от тип Variant, отколкото други определени типове на данни. Както показва следният пример.
Sub VariantTest()
Dim i As Long
Dim ix As Integer, iy As Integer, iz As Integer
Dim vx As Variant, vy As Variant, vz As Variant
Dim tm As Date
vx = 100: vy = 50
tm = Timer
For i = 1 To 1000000
vz = vx * vy
vz = vx + vy
vz = vx - vy
vz = vx / vy
Next i
Debug.Print "Variant types take " & Format((Timer - tm), "0.00000") & " seconds"
ix = 100: iy = 50
tm = Timer
For i = 1 To 1000000
iz = ix * iy
iz = ix + iy
iz = ix - iy
iz = ix / iy
Next i
Debug.Print "Integer types take " & Format((Timer - tm), "0.00000") & " seconds"
End Sub
В горния код редове от 8 до 13 извършват 1 милион операции на събиране, изваждане, умножение и деление на променливи Variant, а редове от 17 до 22 извършват 1 милион операции на събиране, изваждане, умножение и деление на променливи Integer. На моя компютър работата на променливата Variant отне около 0,09375 секунди, докато операцията на променливата Integer отне около 0,03125 секунди. Резултатите може да варират от компютър на компютър, но вариантните променливи са значително по-бавни от целочислените променливи .
Поради тази причина се препоръчва да избягвате използването на променливи Variant, когато можете изрично да използвате указания тип данни .