Macro slows down after change in formula - excel

I used to have this formula below copied into multiple cells, but at some point it wasn't pulling the data properly so I had to modify it to the formula below it. The SUMPRODUCT formula finds data from another spreadsheet based off the part number and pulls it over to the new spreadsheet.
=IFERROR(VLOOKUP($B14,'G:\Locations_NA\TUS\LO\[DMSU MACRO DATA.xlsm]DDCPIV'!$A:$W,13,FALSE),0)
=IFERROR(SUMPRODUCT(('G:\Locations_NA\TUS\LO\[DMSU MACRO DATA.xlsm]DDC SD'!$F$4:$AT$10000)*('G:\Locations_NA\TUS\LO\[DMSU MACRO DATA.xlsm]DDC SD'!$A$4:$A$10000=$B14)*('G:\Locations_NA\TUS\LO\[DMSU MACRO DATA.xlsm]DDC SD'!$F$3:$AT$3=$AD$13)),0)
I run a macro that someone else made which, besides doing other things, fills down this formula a couple hundred rows. Now when I run it with the new formula it takes ages compared to how long it used to take. Is there a better way I can go about this to speed it up?

I would recommend these three basic things, that will help you without modifying much your code.
First: Change VLOOKUP or SUMPRODUCT to "XLOOKUP". This is a faster new formula
it will be something like this
=IFERROR(XLOOKUP(R14C12, _
'G:\Locations_NA\TUS\LO\[DMSU MACRO DATA.xlsm]DDCPIV'!$A:$A, _
'G:\Locations_NA\TUS\LO\[DMSU MACRO DATA.xlsm]DDCPIV'!$W:$W,_
"Error",0),0)
Second: Try to set the formula by a bunch of cells, not one by one (I'm assuming this, if you share more of your code we can check.
one by one is:
Range("A1").FormulaR1C1 =IFERROR(XLOOKUP(R14C12 ...
Range("A2").FormulaR1C1 =IFERROR(XLOOKUP(R15C12 ...
Bunch of cell is:
Range("A1:A5").FormulaR1C1 =IFERROR(XLOOKUP(R14C12 ...
Third: as ENIAC just said, disable UpdatingScreen and other Automatic Updates that Excel has. This will be like this:
Sub Example()
'Beginning Code
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
.DisplayAlerts = False
End With
'Your code Here
'End Code
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
.DisplayAlerts = True
End With
End sub
Now, the best way, in my opinion, is to work with Arrays and Dictionaries, that system is much faster, very much.

Related

Application.Calculate Method doesn't work

I have a complex Excel with lot of tables and formulas.
I stop and resume calculations via VBA code:
Turn OFF calculations:
ActiveSheet.EnableCalculation = False
Application.Calculation = xlCalculationManual
Turn ON calculations:
ActiveSheet.EnableCalculation = True
Application.Calculation = xlCalculationAutomatic
Application.Calculate 'This line calculates all open books and is not strictly necessary.
But still the cells are not calculated.
They are only calculated when I edit each cell with double click and hit Enter (one by one!).
The code doesn't give me any errors and works perfectly on simple books.
The problem is "EnableCalculation" method.
If I remove it, then the book works perfect. So simply toggle ON/OFF calculations with xlAutomatic/xlManual, like this:
Turn OFF calculations:
Application.Calculation = xlCalculationManual
Turn ON calculations:
Application.Calculation = xlCalculationAutomatic

Range.PasteSpecial causes an Application ScreenUpdate in Excel VBA

I have written a VBA Macro for Excel that looks like the following:
Application.ScreenUpdating = False
Dim copyingRange, pastingRange As Range
copyingRange.Cells.Copy
pastingRange.PasteSpecial xlPasteValues
Application.ScreenUpdating = True
It is my understanding that Application.ScreenUpdating = False will force the application to stop screen updates however this is not the behavior I am seeing. I am copying a range from one sheet to another and the application switches views to and from very quickly, an undesirable effect.
Taking out the line pastingRange.PasteSpecial xlPasteValues causes the screen flickering to go away but obviously results in the macro not doing what I want.
Is the pastingRange.PasteSpecial xlPasteValues the problem here? I must be misunderstanding something here?
From comment, so this can be listed as Answered:
You can avoid copy/paste since you just want values and write:
pastingrange.value = copyingrange.value

Excel slow with other spreadsheets open

I have a very simple VBA code running in workbook A that is rather slow when another specific workbook B is open. I don't have access to any macros inside workbook B, so I can't know for sure if anything wierd is happening there.
I've looked around and came with this minimal code condensing the typical solutions I've found in stackoverflow and many Excel specific sites, but it still takes a long time to run.
' Code in workbook A
Sub slow_simple_macro()
With Application
.Calculation = xlCalculationManual
.EnableEvents = False
.ScreenUpdating = False
.DisplayStatusBar = False
End with
Workbooks("workbookA.xlsm").Sheets("Sheet1").Range("A1") = "Slow" ' This line takes about half a second to run when workbook B is open
With Application
.Calculation = xlCalculationAutomatic
.EnableEvents = True
.ScreenUpdating = True
.DisplayStatusBar = True
End with
End Sub
I'm guessing that disabling events is not enough to prevent something inside workbook B from running. Are there any other Application flags I can setup to make it run faster? Any other ideas?
You can see while disabling some functions of excel like calculation mode, screenupdates,status bar would impact on application of Excel because "Excel is the one of The object model that is a large hierarchy of all the objects used in VBA" (Source:www.globaliconnect.com).
So if you want run by turn off application functions , you should be wait till you set back to its original or else same problem would happen.
Better simplify code as possible unless if its required
Sub slow_simple_macro()
Workbooks("workbookA.xlsm").Sheets("Sheet1").Range("A1") = "Slow"
End Sub
Hope you find it as helpful. Have a good day.

Excel VBA correct/efficient formula population

Good Afternoon,
I have been developing solutions in VBA for going on 6 years now. A lot of what I have learned along the way has been sourced from SO in that time, so finally I get a chance to say THANK YOU!
Today I have come to the conclusion that I need to post a question that has been bothering me for years. So - one of the things I do most often in VBA for Excel is to populate defined ranges with results from formulas applied to the range in question. Until now I have used the below method to accomplish this:
Sub CalculateField()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'''''''''''''''''''''''''''''''''
Dim RecordStop As Long
Set MyRange = ActiveSheet.Range("A:A")
RecordStop = Application.WorksheetFunction.CountA(MyRange)
'Apply Formula
Range("M2:M" & RecordStop).FormulaR1C1 = "=IF(RC[-7]=1,IF(ISERROR(VLOOKUP(CONCATENATE(RC[-2],""|"",1),R1C12:R[-1]C[-1],1,FA LSE)),0,1),0)"
'Drop Formula, keep values
Range("M2:M" & RecordStop).Value = Range("M2:M" & RecordStop).Value
''''''''''''''''''''''''''''''''''
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
What I have found is that, although this method works, with larger files/more complex formula the hit I take in performance is HUGE! Now, I know that there must be a more efficient way to derive the results of the formula and inject them directly into the sheet where one wants the results to come back to as values. In the above method I first calculate the results then overwrite the "Formulas" with the "values"(results). I am currently working on a file that will need 21 calculated fields and average between 100k - 400k records.
I fear the time has come for me to learn a better way, the proper more professional way to do this. I have searched here and via the mighty google for examples on how to do this. I have found posts on SO describing what I think is part of the solution, but have had difficulty finding a specific simple example I can follow to implement. I think the correct method involves one or all of the following:
Arrays
Dictionaries
Collections
... I hope you guys can point me in the right direction. This, once solved, I feel will greatly up my game in VBA development. I have been hesitant to delve into this as I am self educated and never really thought I would get this far as it is not my primary role, but would love to get past this now so I would greatly appreciate your assistance.
BTW; I am pretty good at self learning, so if by chance there is already a post that can get me there just point the way. Again, in searching I could not find what I was looking for so I apologize if that was a result of not knowing how to (words to describe) look for the answer.
I might start with this before tinkering a bunch.
If you don't get a performance boost, I'd then consider pulling your source data into Arrays, modify them in code, then write your results in a one line of code write back to your cells.
Here's a great link for working the Array route: VBA Arrays And Worksheet Ranges
Dim PrevCalc As XlCalculation
With Application
PrevCalc = .Calculation
.Calculation = xlCalculationManual
.Cursor = xlWait
.Calculate
.EnableEvents = False
.ScreenUpdating = False
End With
Dim RecordStop As Long
Set MyRange = ActiveSheet.Range("A:A")
RecordStop = Application.WorksheetFunction.CountA(MyRange)
'Apply Formula
With Range("M2:M" & RecordStop)
.FormulaR1C1 = "=IF(RC[-7]=1,IF(ISERROR(VLOOKUP(CONCATENATE(RC[-2],""|"",1),R1C12:R[-1]C[-1],1,FA LSE)),0,1),0)"
'Calc only the target
.Calculate
'Drop Formula, keep values
.Value = .Value
End With 'Range("M2:M" & RecordStop)
With Application
.Cursor = xlDefault
.Calculate
.Calculation = PrevCalc
'.ScreenUpdating = True 'Not Needed...
.EnableEvents = True
End With

Hide Rows based on Cell Data

I want to hide some of the Rows in a worksheet if the Cell in column A contains 0. This is calculated using a formula.
E.g. If A1 contains value "0", row#1 should get hidden.
I know I can write this code on Sheet's Activate Event but it is slowing down the file's performance.
Is there a good way to achieve the same without compromising file's performance?
you could always use filter to achieve this. I think that would be much more efficient.
Edit:
To improve performance of your code, you could do the following:
Turn off the Events
Turn off the Calculations
Before running the loop to hide rows
With Excel.Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
.Cursor = xlWait
End With
After the loop is over
With Excel.Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.Cursor = xlDefault
End With
Hope this helps. Also explicitly using variables could give a boost to performance
and Calculation. Although explicitly declaring your variables should help too.

Resources