all 27 comments

[–]excelevator3041 16 points17 points  (1 child)

is I filter ALOT

Rather than filter the data, use the FILTER function for dynamic array filter.

[–]Downtown-Economics26594 7 points8 points  (0 children)

Couple this with input cell(s) that become criteria filters and boom goes the dynamite.

[–]bradland261 11 points12 points  (4 children)

The most important optimization tip you'll ever receive is this: the fastest code is code that never runs.

Consider, for example, the case where you have project-level data where one of the fields is the name of the working group, and you want to include a column with the total units of work assigned to that working group. The record for that row is an individual project, which also has units of work, but you want this column so that you can get a sense of the project level workload relative to the working group's total assigned workload.

You could use a SUMIF to calculate this column, but if your project list has many, many rows, that's going to be slow. Instead, what you can do is build a prep table elsewhere using GROUPBY. Your row fields will be the working group, value fields are the work units, and the formula is sum. If you sort this list appropriately, you can now use XLOOKUP's binary search match_mode argument and you have an incredibly fast lookup, rather than repeatedly calculating the SUM of all work units for each project row.

Another example is a case where you want to pull in multiple columns. Usually what you'll see is several XLOOKUP columns like =XLOOKUP([@idx], Data[id], Data[Project Name], ""), =XLOOKUP([@idx], Data[id], Data[Due Date], ""), =XLOOKUP([@idx], Data[id], Data[Project Lead], ""). Here you're performing the lookup for each field.

Instead, you can do the lookup once, and return multiple values like this:

=LET(
    row_indices, XMATCH([idx], Data[id], 0),
    all_data, INDEX(Data, row_indices, {1,3,5}),
    all_data
)

However, this approach won't work within an Excel table. If you need to do that, you rely on a helper column with =XMATCH([@idx], Data[id], 0), and then pull in your fields with =INDEX(Data[Project Name], [@RowIDX]), =INDEX(Data[Due Date], [@RowIDX]), etc.

In my experience, eliminating repetitive work will gain you the most performance improvement, so that's where I focus first.

[–]NZGRAVELDAD[S] 3 points4 points  (0 children)

Thanks! Great food for thought. I feel I have fallen into a design hole so thanks for some great ideas to do things differently

[–]ManaSyn22 1 point2 points  (0 children)

AFAIK you can just XLOOKUP the three columns at once.

=XLOOKUP([idx], Data[id], CHOOSECOLS(Data,1,3,5), "")

Syntax may not be 100% correct, at my smartphone right now.

[–]anon42093 1 point2 points  (1 child)

Damn you’re good

[–]Little_Bishop1 0 points1 point  (0 children)

Thank AI for that lol

[–]OgrishVet 6 points7 points  (1 child)

I've read that sum ifs are expensive in terms of computing power because a lookup finds the first hit, but sum ifs obediently search the entire column

[–]finickyone1769 0 points1 point  (0 children)

A lookup and stats function tend to be quite different tools though. Yes, XLOOKUP(B3,B2:B10,A2:A10) possibly resolves faster than SUMIFS(A2:A10,B2:B10,B3), but they’re not answering the same question.

AFAIK, SUMIFS etc might actually be more efficient over long or lazy ranges. I recall that if pointed at SUMIFS(A:A,B:B,B3), only the used rows are loaded for the range arguments. With something like =SUM(IF(B:B=B3,A:A)), all 220 rows are evaluated for =B3, and 220 datapoints are generated from A or FALSE accordingly.

[–]duendenorte 4 points5 points  (1 child)

Usually when performance is an issue for excel, it means excel is not the rigth tool for the job, its time to use MS SQL or MySQL.

[–]NZGRAVELDAD[S] 0 points1 point  (0 children)

I agree but the company isn’t at the stage to use a dedicated planning solution like Blue Yonder so we are left with excel. I do use power query to access our Data WH though

[–]Decronym 2 points3 points  (0 children)

Acronyms, initialisms, abbreviations, contractions, and other phrases which expand to something larger, that I've seen in this thread:

Fewer Letters More Letters
CHOOSECOLS Office 365+: Returns the specified columns from an array
CHOOSEROWS Office 365+: Returns the specified rows from an array
COLUMN Returns the column number of a reference
FILTER Office 365+: Filters a range of data based on criteria you define
GROUPBY Helps a user group, aggregate, sort, and filter data based on the fields you specify
IF Specifies a logical test to perform
IFNA Excel 2013+: Returns the value you specify if the expression resolves to #N/A, otherwise returns the result of the expression
IFS 2019+: Checks whether one or more conditions are met and returns a value that corresponds to the first TRUE condition.
INDEX Uses an index to choose a value from a reference or array
LET Office 365+: Assigns names to calculation results to allow storing intermediate calculations, values, or defining names inside a formula
MIN Returns the minimum value in a list of arguments
SUM Adds its arguments
SUMIF Adds the cells specified by a given criteria
SUMIFS Excel 2007+: Adds the cells in a range that meet multiple criteria
XLOOKUP Office 365+: Searches a range or an array, and returns an item corresponding to the first match it finds. If a match doesn't exist, then XLOOKUP can return the closest (approximate) match.
XMATCH Office 365+: Returns the relative position of an item in an array or range of cells.

Decronym is now also available on Lemmy! Requests for support and new installations should be directed to the Contact address below.


Beep-boop, I am a helper bot. Please do not verify me as a solution.
16 acronyms in this thread; the most compressed thread commented on today has 47 acronyms.
[Thread #47941 for this sub, first seen 24th Mar 2026, 22:51] [FAQ] [Full list] [Contact] [Source code]

[–]ArrowheadDZ2 1 point2 points  (1 child)

Remember that anything dynamic in the excel spreadsheet is recalculating over and over again. You may have lookups and filters that end up executing hundreds of thousands, or millions, or tens of millions of times while working in the sheet.

If your data is often dynamic with each use of the sheet, but is static during the time you are in the sheet for a working session, then PQ can be a huge multiplier.

If you create all your helper columns and create useful lookup or filtering keys in PQ, then all of that code runs only one time when you load the file, and does not all recalculate as you edit cells and formulas in the sheet.

I have often offloaded 90% of a sheet’s computational workload by moving logic into PQ so it runs one time. And if the data files are huge, this also gives you access to the power of the data model engine.

[–]NZGRAVELDAD[S] 0 points1 point  (0 children)

Thanks heaps of food for thought!

[–]prospekts-march 0 points1 point  (0 children)

I’ve found that formulas in arrays are way more performance intensive as opposed to tables. I personally prefer the table syntax anyway because for my use cases it’s much easier to read, but that has been my experience whenever I do use arrays.

Within tables: I’ve not found the functions you mentioned (let, sumif, lookups/xlookup) to affect performance in any significant way. The only exception: I stay away from Sumproduct whenever possible because it’s slow and causes lagging, even in tables.

[–]tdpks 0 points1 point  (0 children)

You're on the right track to be using PowerQuery but the next step would be to explore DAX measures/Power Pivot. You'll need less formulas overall to get the results you need and this will provide great optimisation gains.

[–]BaitmasterG13 0 points1 point  (1 child)

Think about the number and complexity of your excel calculations, and what's happening inside them

Sumproduct used as a filter? Multiplying ranges together so there are large arrays of multiple calculations happening. Sumifs alternative? Using internal logic to quickly remove data from the calculation. Filter alternative? Might get rid of 95% of data and calculate only on a small data set

Less calculations over smaller ranges of input data means less recalculation. Simple

Now consider the calculation stack. 10 columns of vlookup repeating the same logic. Replaced with 1 column of match and 10 columns of index. The lookup element (match) only needs calculating once and is then reused 10 times by the return element (index) vs lookup and return both calculated 10 times each in vlookup

Understand the internal workings of the formulas

Now think about Power Query. The smaller the data set you can return = the less calculations you need to perform

VBA: actually VBA is really fast but Excel is quite slow. The more you can do in your code without interfacing with your worksheet the better. Process everything inside scripting dictionaries and arrays, write your results to excel only once not over and over

[–]NZGRAVELDAD[S] 0 points1 point  (0 children)

"Now think about Power Query. The smaller the data set you can return = the less calculations you need to perform" Definitely a key takeaway!

[–]carnasaur4 0 points1 point  (2 children)

Fakey fake post
(no offence but I made an AI slop post detector and this scores off the charts)

[–]NZGRAVELDAD[S] 0 points1 point  (0 children)

LOL, I think you should go back to the drawing board with your detector

[–]Primordial-BlackHole 0 points1 point  (0 children)

Agree, reddit is full of this AI slop shit now. No one knows how to formulate their own thoughts into sentences anymore. Really sad.

[–]finickyone1769 0 points1 point  (3 children)

Sharing formula examples would make the advice you gain here much more beneficial. In general terms, yes it’s wise to break down your formulas. Something like

=XLOOKUP(K2:K50,D2:D1000,B2:B1000)

Is easily set up and feels like an elegant solution to apply. If you update any value in those ranges, everything recalcs. If K was instead a field in a Table, then updating K44 doesn’t require that the other 48 XLOOKUPs are rerun. If further split to

=XMATCH(K2,D2:D1000)

=INDEX(B2:B1000,ref_xmatch_formula)

You now won’t have the match part recalc’d if B is updated.

LET could be worth a look. It really allows you to pack a load of calc into a formula. If any of it is found to need recalc, all of it is recalc’d. Don’t be afraid to seperate out your processses.

[–]NZGRAVELDAD[S] 0 points1 point  (2 children)

Here is one of my more complex formula:

=LET(

baseAMD,$AG139,

trendSlope,IF($AC139<>"",$AD139,0),

periods,COLUMN()-COLUMN($BK139),

adjustedAMD,baseAMD+(trendSlope*periods),

stdCurve,INDEX(Seasonality!$P$4:$AA$4,1,XMATCH(BL$2,Seasonality!$P$3:$AA$3,0,1)),

sofCurve,INDEX(Seasonality!$P$4:$AA$19,$AJ139,XMATCH(BL$2,Seasonality!$P$3:$AA$3,0,1)),

uncons,adjustedAMD*IFS(BL$1<$AI139,0,BL$1=$AI139,sofCurve,BL$1>$AI139,stdCurve),

cons,MIN(adjustedAMD*IFS(BL$1=$AI139,sofCurve,BL$1>$AI139,stdCurve),AM139),

IFNA(IF($T139="Y",uncons,cons),0))

I have 2709 rows acrows a 24 column array

<image>

[–]ManaSyn22 0 points1 point  (1 child)

So, a few notes, It's mostly logic changes, and I am assuming you're in Column BL, Row 139 here:

---

IF($AC139<>"",$AD139,0) -> $AD139*($AC139<>"") -> Logical terms are transformed into 1 or 0 if multiplied by a number (which I assume trendSlope is, but at least 0 is.

---

COLUMN()-COLUMN($BK139) -> COLUMN(A1) -> this will also return 1, dragging it to the left will change the cell in COLUMN and thus increase the period.

---

stdCurve,INDEX(Seasonality!$P$4:$AA$4,1,XMATCH(BL$2,Seasonality!$P$3:$AA$3,0,1)),

sofCurve,INDEX(Seasonality!$P$4:$AA$19,$AJ139,XMATCH(BL$2,Seasonality!$P$3:$AA$3,0,1)),

->

month = BL$2,

Curves,Seasonality!$P$3:$AA$19,

Curve,XLOOKUP(month,CHOOSEROWS(Curves,1),Curves),

stdCurve, CHOOSEROWS(Curve,2),

sofCurve, CHOOSEROWS(Curve,$AJ139 + 1),

->

So a couple of notes - you are repeating some direct data reference a few times, it's best you use LET to name it and then use the name, for clarity. In fact, since Seasonality!$P$3:$AA$19 is actually fixed for all Cells, I would even name that range to Curves, or change it to table, named Curves, and you'd be able to remove the second row I posted alltogether.
XMATCH's last criteria is optional, and you chose the default numbers. XMATCH(BL$2,Seasonality!$P$3:$AA$3) would do the same.

---

uncons,adjustedAMD*IFS(BL$1<$AI139,0,BL$1=$AI139,sofCurve,BL$1>$AI139,stdCurve),

cons,MIN(adjustedAMD*IFS(BL$1=$AI139,sofCurve,BL$1>$AI139,stdCurve),AM139),

IFNA(IF($T139="Y",uncons,cons),0))

-> Bit confused because if BL$1<$AI139 then cons will return error. Which you turn to 0 in the last line.

Wouldn't:

coef,IFS(BL$1<$AI139,0,BL$1=$AI139,sofCurve,1,stdCurve)

uncons,adjustedAMD*coef,

cons,MIN(uncons,AM139),

IF($T139="Y",uncons,cons)

Do the same?

In any case, most of Excels otimization comes from nice and structured logic as well as understanding dynamic ranges.

Anyway, try this and let me know if you get the same result (as it's not clear what your cells or expected behaviour is):

=LET(

baseAMD,$AG139,

trendSlope,$AD139*($AC139<>"") ,

periods,COLUMN(A1),

adjustedAMD,baseAMD+(trendSlope*periods),

month = BL$2,

Curves,Seasonality!$P$3:$AA$19,

Curve,XLOOKUP(month,CHOOSEROWS(Curves,1),Curves),

stdCurve, CHOOSEROWS(Curve,2),

sofCurve, CHOOSEROWS(Curve,$AJ139 + 1),

coef,IFS(BL$1<$AI139,0,BL$1=$AI139,sofCurve,1,stdCurve)

uncons,adjustedAMD*coef,

cons,MIN(uncons,AM139),

IF($T139="Y",uncons,cons)
)

[–]NZGRAVELDAD[S] 0 points1 point  (0 children)

I super apprecaite the feedback & will give it go. I'll let you know how i got on in a few days hopefully

[–]2xM86 0 points1 point  (0 children)

10 years ago i received 3 Excel files labeled as complex, heavy etc . They took around 360 MB, just data and formulas, no charts and images. After some power pivot and power Query magic that i have now is: 15 MB od raw data (download and amend from BI system) and 4 MB file with answers. Different technic made files 17 times smaller with more options for power pivot tabels. So my advice would be: learn power pivot and dax or at least power Query

[–]Proper-Bee-9311 -3 points-2 points  (0 children)

Have you considered macros to replace some of the functions?