You are on page 1of 6

17 ways to Optimize VBA Code for FASTER Macros

TUTORIALS VBA MACRO


On the eve before Christmas, I'm writing this article on VBA code optimization for my
blog readers as a gift. It contains both the knowledge and good practices which if
followed and used effectively then it might put you in elite category of excellent VBA
programmers. VBA programs are known to save a lot of time and now this post is to
save further time. Read them carefully and open new pathways of innovation in
creating excel dashboards, reports and automation. Wish my readers a very MerRy
ChRisTMaS !

Here is a summary of the article:


1. Analyze the Logic 2. Turn off ScreenUpdating
3. Turn off 'Automatic Calculations' 4. Disable Events
5. Hide Page breaks 6. Use 'WITH' statement
7. Use vbNullString instead of "" 8. Release memory of Object
variables
9. Reduce the number of lines using colon(:) 10. Prefer constants
11. Avoid Unnecessary Copy and Paste 12. Clear the Clipboard after Paste
13. Avoid 'Macro Recorder' style code. 14. Use 'For Each' than 'Indexed For'
15. Use 'Early Binding' rather 'Late Binding' 16. Avoid using Variant
17. Use Worksheet Functions wherever applicable

Do read full article to understand the logic behind them.

Analyze the logic: Before optimizing the syntax, pay more attention in optimizing the
logic. Without a good logic, a good written VBA macro program has no value. So
streamline your program logic and get the best performance of macros.

Avoid 'Screen Flickering' or 'Screen Repainting': Use


Application.ScreenUpdating = False 'To Turn Off at the start of code.
Application.ScreenUpdating = False 'To Turn on at the end of the code.

The ScreenUpdating property controls most


display changes on the monitor while a
procedure is running. When screen
updating is turned off, toolbars remain
visible and Word still allows the procedure
to display or retrieve information using
status bar prompts, input boxes, dialog
boxes, and message boxes. You can
increase the speed of some procedures by
keeping screen updating turned off. You
must set the ScreenUpdating property to
True when the procedure finishes or when it
stops after an error. Refer MSDN for
details.
Turn off automatic calculations: Whenever content(s) of a cell or range of cells are
changed, the formulas dependent on them and Volatile functions are recalculated.
You may turn off the automatic calculation using
Application.Calculation = xlCalculationManual 'To turn off the automatic calculation
Application.Calculation = xlCalculationAutomatic 'To turn On the automatic
calculation
Now, whenever due to the program logic(that due to macros dependent on existing
formulas) you need to calculate the formulas, you may use the following code
accordingly.
ActiveSheet.Calculate ' To calculate the formulas of Active Worksheet
Application.Calculate ' To calculate the formulas of Active workbook or all workbooks
in current application.

Stop Events: Use Application.EnableEvents to tell VBA processor whether to fire


events or not. We rarely fire an event for each cell we're changing via code. Hence,
turning off events will speed up our VBA code performance.

Hide Page Breaks:When we run a Microsoft VBA macro in a later version of Microsoft
Excel, the macro may take longer to complete than it does in earlier versions of
Excel. For example, a macro that required several seconds to complete in an earlier
version of Excel may require several minutes to complete in a later version of Excel.
This problem may occur if the following conditions are true:

* The VBA macro modifies the properties of


many rows or columns.
* An operation has been performed that
forced Excel to calculate page breaks.
Excel calculates page breaks when we
perform any of the following operations:

o We display a print preview of your


worksheet.
o In Microsoft Office Excel 2003 and in
earlier versions of Excel, we click Page
Setup on the File menu.
o We modify any of the properties of the
PageSetup object in a VBA macro.
* In Excel 2003 and in earlier versions of
Excel, we selected the Page breaks check
box on the View tab of the Options dialog
box.
Solution: is to disable Page breaks using ActiveSheet.DisplayPageBreaks = False
Refer to this Microsoft article for more details -
http://support.microsoft.com/kb/199505

Use 'WITH' statement when working with objects: If we have to access an object's
properties and methods in several lines, we must avoid using object's name or fully
qualified object path again and again. It is annoying for VBA processor as it needs to
fully qualify the object each time. (Isn't it annoying for us too when some work or
something is told us again and again? Got it Guys !
SLOW MACRO
FAST MACRO
With Sheets(1).Range("A1:E1")
.Font.Italic = True
Sheets(1).Range("A1:E1").Font.Italic = True
.Font.Interior.Color = vbRed
Sheets(1).Range("A1:E1").Font.Interior.Color = vbRed
.MergeCells = True
Sheets(1).Range("A1:E1").MergeCells = True
End With
The point here to understand is minimum qualifying of an object by VBA processor.
i.e. using minimum dots/periods(.) in the code. This concept tells us to use [A1]
rather than Range("A1") and Range("StockRange")(3,4) rather than
Range("StockRange").Cells(3,4)

Use vbNullString instead of ""(2 double quotes) : vbNullString is slightly faster than
"", since vbNullString is not actually a string, but a constant set to 0 bytes, whereas ""
is a string consuming at least 4-6 bytes for just existence.
For example: Instead of strVariable = "", use strVariable = vbNullString.

Release memory from object variables: Whenever we create an object in VBA, we


actually create two things -- an object, and a pointer (called an object reference).
We might say, "VB does not use pointers", but it is not true. "VB does not let you
manipulate pointers" is more precise. Behind the scenes, VB still makes extensive use
of pointers. To destroy an object in VB, you set it to Nothing. But wait a minute. If all
we ever use are object pointers, how can we set the object itself to Nothing? The
answer is: We can't.
When we set a reference to Nothing, something called the garbage collector kicks in.
This little piece of software tries to determine whether or not an object should be
destroyed. There are many ways to implement a garbage collector, but Visual Basic
uses what is called the reference count method.
When VB interprets the last line(where we generally sets our objects to Nothing), it
will remove the existing reference. At this point, if the object has no more
references, the garbage collector will destroy the object and deallocate all its
resources. If any other references point to the same object, the object will not be
destroyed.

Reduce the number of Lines: Avoid multiple statements especially when they can be
clubbed into one line. For example - See these 2 macros
SLOW MACRO FAST MACRO

With Selection
.WrapText = True With Selection
.ShrinkToFit = False .WrapText = True: .ShrinkToFit = False
End With End With
As you can see, you can club multiple statements into one using colon character(:).
When you do this with multiple statements, it will decrease the readability but will
increase the speed.
Compiler Logic: When we save the macro, it is virtually compiled and unlike it's
human readable form as we saw in VBE(Visual Basic Editor), keywords(the dark blue
words which you cannot use as variable) are saved as three-byte token which are
faster to process as machine understand them better and variables, comments and
literal strings which are not either keyword or directive are saved "as is". However
VBA compiler tokenizes the word but it does not compress the lines and each line is
maintained as is ending with the 'Carriage Return'. When the VBA macro is executed,
VBA processor fetched single line at a time. The tokens of the fetched line saved by
virtual compiler are now interpreted and executed then next line is fetched and so
on. When we combine multiple lines using colon into one line, we're reducing the
number of fetch cycles the processor must go through.
Our Suggestion: This change will bring minor difference in time due to faster
processors today. Moreover, you cannot have more than 255 characters in a line and
you won't be able to debug your code using F8 efficiently. So it's a kind of useless,
there is no reason to trade-off with readability with such a minor change in time.

Declare variable as Variable and constant as Constant: Seems, obvious ! But many of
us don't follow it. Like
Dim Pi As Double
Pi = 3.14159
instead use
Const Pi As Double
Pi = 3.14159
Since, its value is never changed so it will be evaluated once during compilation
unlike variable which are evaluated many times during the run-time.

Avoid Unnecessary Copy and Paste: Follow this table rules:


Instead of Use this:
Sheet1.Range("A1:A200").Copy
'Bypass the Clipboard
Sheet2.Range("B1").PasteSpecial
Sheet1.Range("A1:A200").Copy Destination:=
Application.CutCopyMode = False
Sheet2.Range("B1")
'Clear Clipboard
Sheet1.Range("A1:A200").Copy
Sheet2.Range("B1").PasteSpecial 'Bypass the Clipboard if only values are required
xlPasteValues Sheet2.Range("B1:B200").Value =
Application.CutCopyMode=False Sheet1.Range("A1:A200").Value
'Clear Clipboard
'Bypass the Clipboard if only formulas are required
Sheet1.Range("A1:A200").Copy
Sheet2.Range("B1:B200").Formula =
Sheet2.Range("B1").PasteSpecial
Sheet1.Range("A1:A200").Formula
xlPasteFormulas
Application.CutCopyMode=False
'Same can be done with FormulaR1C1 and Array
'Clear Clipboard
Formulas.

Use Worksheet Functions rather developing own logic: By using


Application.WorkSheetFunction, we tell VBA processor to use native code rather than
interpreted code as VBA understands the worksheet functions better than your
algorithm. So, for example use
mProduct = Application.WorkSheetFunction.Product(Range("C5:C10"))
rather than defining your own logic like this:
mProduct = 1
For i = 5 to 10
mProduct = mProduct * Cells(3,i)
Next

Use 'For Each' rather than 'indexed For': We can avoid using Indexed For when
looping through collections. For example, take the code just before this tip. It can be
modified to:
For Each myCell in Range("C5:C10")
mProduct = mProduct * myCell.Value
Next
This is in relation to qualifying object again and again as using "WITH" statements.

Avoid using 'Macro Recorder' style code:Ya, the code will look genius and eventually
perform like Genius too ! You'll better catch it with example, so use:
[A1].Interior.Color = vbRed
rather than
Range("A1").Select
Selection.Interior.Color = vbRed
Using too many Select and Selection effects the performance drastically. Ask yourself
why to go in Cell and then change the properties? or rather ask why to go pizza shop
when you can enjoy it at your home ;)

Avoid using Variant and Object in declaration statements: Think about better logic
and get rid of them. i.e. do not use Dim i As Variant or Dim mCell As Object. By trying
to be specific,we will save a lot of system memory this way, particularly in case of
large projects. We may not remember which has been declared variant above and
misuse a variable assigning any value to it which will be type-casted without errors. A
variant's descriptor is 16 bytes long while double is 8 bytes, long is 4 bytes and integer
is 2 bytes. Hence use Variant cautiously. As an example, use:
Dim i As Long rather than Dim i As Variant
Similarly use:
Dim mCell As Range 'or
Dim mSheet As Worksheet
rather than
Dim mCell As Object 'or
Dim mSheet As Object

Declare OLE objects directly: Declaring and defining the OLE objects in declaration
statement is called 'Early Binding' but declaring an object and defining it later is
called 'Late Binding'. Always prefer 'Early Binding' over 'Late Binding'. Now for example
use:
Dim oXL As Excel.Application
rather than
Dim oXL As Object
Set oXL = CreateObject("Excel.Application")

You might also like