系列 · Excel 函数学习与实战 第 9 篇 / 共 9 篇 教程

告别重复 SUMIFS:用 GROUPBY + XLOOKUP 重构高性能汇总公式

用真实报表公式讲清如何把反复扫描源表的 SUMIFS,改造成 GROUPBY 一次汇总、XLOOKUP 批量查回,并说明什么时候值得这样改。

作者:黄撑 更新于 2026-08-19
本文目录 18 节 · 点击展开

很多 Excel 报表真正拖慢计算的,不一定是某个公式“写得很长”,而是同一份源数据被反复做同一种汇总

最典型的场景就是:目标表有几百、几千个 Key,每一行都要去订单明细里按条件求和。习惯上很容易写成 SUMIFS,而当目标查询越来越多时,也就意味着同一份源表要被不断重新参与条件汇总。

这类问题可以换一个思路:先把源数据集中汇总一次,再让所有目标去查这个汇总结果。

EXCEL FORMULA · HOW IT RUNS同一份源数据,只做一次汇总

先拼 Key,再把重复行压成唯一 Key 小表,最后让全部目标去小表中查结果。

计算结构1 次汇总+ 批量查回
压缩前8 行明细重复 Key 分散在多行
集中汇总一次GROUPBY相同 Key 合并
压缩后4 行结果每个 Key 只留一个 SUM
  1. 01源表
  2. 02拼 Key
  3. 03GROUPBY
  4. 04唯一 Key 小表
  5. 05TAKE 拆列
  6. 06XLOOKUP
01 · 源表订单明细有重复 Key
日期商品直播间金额
8/101001A120
8/101001A80
8/101002A90
8/111001A60
8/111001F2150
大量明细行同一组合可能出现多次
02 · srcKey逐行拼成组合 Key
8/10+1001+A
8/10¦1001¦A
8/11+1001+F2
8/11¦1001¦F2
日期 & CHAR(1) & 商品ID & CHAR(1) & 直播间
03 · GROUPBY按 Key 集中汇总一次
输入重复 Key + 金额GROUPBYSUM · 0 · 0输出唯一 Key + SUM
8 行 → 4 行演示数据被一次压缩
04 · g生成唯一 Key 小表
KeySUM
8/10¦1001¦A200
8/10¦1002¦A90
8/11¦1001¦A60
8/11¦1001¦F2150
小结果集后续不再面对完整明细
05 · TAKE拆成查找列和返回列
TAKE(g,,1)查找列8/10¦1001¦A8/10¦1002¦A8/11¦1001¦A
TAKE(g,,-1)返回列2009060
06 · XLOOKUP所有目标批量查回
8/10¦1001¦A匹配200
8/11¦1001¦F2匹配150
8/11¦1001¦A匹配60
XLOOKUP(targetKey, 查找列, 返回列, 0)
srcKeyGROUPBYg:Key | SUMTAKEXLOOKUP
核心公式每个变量都能在上面的中间结果中找到
=LET(srcKey, 平台订单明细!I2#&CHAR(1)&平台订单明细!C2#&CHAR(1)&平台订单明细!A2#,targetKey, CHOOSECOLS(A2#,3)&CHAR(1)&CHOOSECOLS(A2#,2)&CHAR(1)&CHOOSECOLS(A2#,1),g, GROUPBY(srcKey, 平台订单明细!F2#, SUM, 0, 0),XLOOKUP(targetKey, TAKE(g,,1), TAKE(g,,-1), 0))
为什么传统写法容易累积重复计算每增加一个目标,SUMIFS 都要再次面对同一份源表
同一源表完整订单明细
目标 01扫描一次目标 02再扫描目标 03再扫描目标 N继续扫描
性能收益来自减少重复汇总不是因为新函数的名字天然更快

先说结论:这不是“GROUPBY + XLOOKUP 在任何情况下都一定比 SUMIFS 快”。

  • 源数据只有几百行、目标查询也很少时,两种写法通常都很快,没必要为了优化而优化。
  • 数据量越大、目标查询行越多、同一份源数据被重复汇总的次数越多,先 GROUPBYXLOOKUP 的价值通常越明显。
  • 真正值得学习的是这套计算结构:一次汇总 → 生成较小结果集 → 批量查回。

兼容性提醒:本文核心函数 GROUPBY 当前适用于 Microsoft 365。若你的 Excel 版本没有 GROUPBY,不要直接照搬本文公式。

一、一个很典型的 SUMIFS:每个目标都去源表汇总

假设目标表 A2# 每一行代表一个:

日期 + 商品 ID + 直播间

现在要去 平台订单明细 中,把对应组合的 F 列金额或件数汇总回来。

最直接的写法是:

=SUMIFS(
    平台订单明细!F2#,
    平台订单明细!I2#,
    CHOOSECOLS(A2#,3),
    平台订单明细!C2#,
    CHOOSECOLS(A2#,2),
    平台订单明细!A2#,
    CHOOSECOLS(A2#,1)
)

业务上很好理解:

条件源数据字段目标表字段
直播间平台订单明细!I2#CHOOSECOLS(A2#,3)
商品 ID平台订单明细!C2#CHOOSECOLS(A2#,2)
日期平台订单明细!A2#CHOOSECOLS(A2#,1)
汇总值平台订单明细!F2#SUM

公式本身没有错。问题出现在目标行很多的时候。

目标表里有一个组合,就要算一次这个组合;再多一个组合,又要继续针对相同源数据做条件汇总。单次并不一定慢,但当这种结构出现在很多列、很多 Sheet、很多目标行时,重复计算会不断累积。

平台订单明细同一份源数据订单行不断增加
目标 01直播间 A + 商品 1001 + 8/10汇总一次
目标 02直播间 A + 商品 1002 + 8/10再汇总
目标 03直播间 B + 商品 1001 + 8/11再汇总
……目标组合继续增加继续计算

所以需要优化的不是“SUMIFS 这个函数”,而是:不要让大量目标反复做同一类源表汇总。

二、先认识 GROUPBY:把源表一次压缩成汇总表

先别急着看组合 Key。GROUPBY 最基本的写法只有三部分:

=GROUPBY(
    分组字段,
    汇总字段,
    SUM
)

例如:

=GROUPBY(
    CHOOSECOLS(A2#,1),
    D2#,
    SUM
)

它的意思就是:按照 A2# 第一列分组,把同一个 ID 对应的 D2# 自动求和。

假设源数据是:

ID金额
A10
A20
B5

经过 GROUPBY 后,核心结果就变成:

IDSUM
A30
B5
汇总前3 行明细
ID金额
A10
A20
B5
同 Key 合并GROUPBYSUM3 行 → 2 个 Key
汇总后唯一 Key 小表
IDSUM
A30
B5

基础写法会使用 GROUPBY 的默认表头和总计规则,因此实际结果还可能出现总计行。后面要把结果交给 XLOOKUP 时,我会明确写成 GROUPBY(...,0,0),让 g 只保留用于查找的分组字段和汇总值。

这一步非常关键:原来可能有几万行订单,汇总后只剩下“唯一 Key + 汇总值”。后面的查询不再面对完整订单明细,而是面对这个已经压缩过的小结果集。

CHOOSEROWS 和 CHOOSECOLS 不要写反

动态数组里很容易把这两个函数搞混:

=CHOOSEROWS(A2#,1)

这是取第一行

=CHOOSECOLS(A2#,1)

这才是取第一列

如果只是要第一列,也可以写:

=TAKE(A2#,,1)

三者没有必要混着炫技。知道自己要的是“行”还是“列”就够了。

三、TAKE:把 GROUPBY 结果拆成“查找列”和“返回列”

后面会频繁看到这两个写法:

=TAKE(g,,1)

表示:取数组 g 的第一列。

=TAKE(g,,-1)

表示:从末尾取 1 列,也就是取 g 的最后一列。

所以:

=XLOOKUP(
    target,
    TAKE(g,,1),
    TAKE(g,,-1),
    0
)

翻译成人话就是:

目标target KeyA
g 的第一列g 的最后一列
A30
B5
TAKE(g,,1)TAKE(g,,-1)
XLOOKUP 返回30A 命中第一行

也就是:用目标 Key → 去 GROUPBY 第一列找 → 返回 GROUPBY 最后一列的汇总结果。

四、先看最简单的单 Key 版本

假设以前的需求只是:按照 ID 汇总金额,再把结果对应到 A2#

原来可能写:

=SUMIFS(金额列,ID列,A2#)

可以改成:

=LET(
    g,
    GROUPBY(
        ID列,
        金额列,
        SUM,
        0,
        0
    ),
    XLOOKUP(
        A2#,
        TAKE(g,,1),
        TAKE(g,,-1),
        0
    )
)

这里的逻辑只有两步:

  1. GROUPBY 把同一个 ID 的金额先合并成一行。
  2. XLOOKUP 把每个目标 ID 的汇总值一次查回来。

这里特意写了 GROUPBY(...,0,0)

  • 第 4 个参数 0:不把源数组当作带表头的数据,也不输出字段表头。
  • 第 5 个参数 0:不生成总计行。

这样 g 就保持最适合查找的两列结构:Key | 汇总值

如果只有几百行数据、几十个查询,这种改造未必会让你肉眼感觉到速度变化。它的意义是先建立正确结构,等源表和查询数量上来以后,不需要让同一类汇总继续无限复制。

五、真实多条件场景:组合 Key + GROUPBY + XLOOKUP

回到开头的真实业务:

直播间 + 商品 ID + 日期

这里需要把三个条件先变成一个唯一组合 Key。

完整公式:

=LET(
    srcKey,
    平台订单明细!I2#&CHAR(1)&
    平台订单明细!C2#&CHAR(1)&
    平台订单明细!A2#,
    targetKey,
    CHOOSECOLS(A2#,3)&CHAR(1)&
    CHOOSECOLS(A2#,2)&CHAR(1)&
    CHOOSECOLS(A2#,1),
    g,
    GROUPBY(
        srcKey,
        平台订单明细!F2#,
        SUM,
        0,
        0
    ),
    XLOOKUP(
        targetKey,
        TAKE(g,,1),
        TAKE(g,,-1),
        0
    )
)

看起来比一条 SUMIFS 长,但它其实只是把处理过程明确拆成了三个阶段:

01 · 组合 Key先把三个条件变成一个值
直播间 A+商品 1001+8/10
srcKey / targetKey
02 · 一次汇总重复 Key 在这里合并
A¦1001¦8/1010A¦1001¦8/1020A¦1001¦8/1030
g = GROUPBY(…)
03 · 批量查回目标只查询压缩后的小表
targetKey命中30
XLOOKUP(…)

1. srcKey:把多个条件拼成一个 Key

srcKey,
平台订单明细!I2#&CHAR(1)&
平台订单明细!C2#&CHAR(1)&
平台订单明细!A2#

原来三个独立条件:

直播间 A
商品 1001
2026/8/10

现在把它们拼成一个用于匹配的组合值。

targetKey 做完全相同的事情,只不过来源换成目标表 A2#

组合 Key 只负责把多个字段连接起来,不会自动修正数据类型。如果源表里的日期是真正的日期值,而目标表里的日期是文本,两边拼出来的 Key 仍然可能不同;实际使用时要先保证参与拼接的字段口径一致。

2. 为什么用 CHAR(1),而不是 *

很多人拼 Key 会这样写:

=直播间&"*"&商品ID&"*"&日期

能不能用?当然能。

* 是正常业务文本中有可能出现的字符。如果字段本身也包含 *,组合值的边界就不够干净。

这里使用:

CHAR(1)

它对应一个业务文本里极少出现的控制字符,用作分隔符时,更不容易和真实字段内容撞在一起。

重点不是必须迷信 CHAR(1),而是:组合 Key 的分隔符应该尽量避免出现在业务数据本身。

3. GROUPBY:把整个源表按 Key 汇总一次

g,
GROUPBY(
    srcKey,
    平台订单明细!F2#,
    SUM,
    0,
    0
)

假设组合后得到:

srcKeyF 列
A10
A20
B5

GROUPBY 后就是:

Key汇总结果
A30
B5

源表里的重复 Key 被压成了唯一 Key。

4. TAKE(g,,1):取第一列 Key

TAKE(g,,1)

得到:

A
B

5. TAKE(g,,-1):取最后一列汇总值

TAKE(g,,-1)

得到:

30
5

6. XLOOKUP:所有目标一次查回

XLOOKUP(
    targetKey,
    TAKE(g,,1),
    TAKE(g,,-1),
    0
)

现在目标表已经不需要继续面对完整订单明细。它只需要去 g 这张已经汇总好的小表里找结果。

六、日期范围场景:先 FILTER,再 GROUPBY,再 XLOOKUP

另一个非常常见的报表需求是:

只统计某个日期范围内,每个 ID 的金额。

例如统计 N1P1 之间的直播花费:

=LET(
    ids,【辅助】直播花费分摊!B2#,
    dt,【辅助】直播花费分摊!A2#,
    amt,【辅助】直播花费分摊!G2#,
    f,FILTER(
        HSTACK(ids,amt),
        (ids<>"")*(dt>=N1)*(dt<=P1)
    ),
    g,GROUPBY(
        TAKE(f,,1),
        TAKE(f,,-1),
        SUM,
        0,
        0
    ),
    XLOOKUP(
        A2#,
        TAKE(g,,1),
        TAKE(g,,-1),
        0
    )
)

不要从外往里硬读。按执行路径看就很简单:

源数据ID + 日期 + 金额
FILTER日期范围只筛一次N1 ≤ dt ≤ P1
GROUPBY筛选结果只汇总一次ID → SUM(金额)
XLOOKUP目标 ID 批量查回A2# → 汇总结果

这类结构特别适合周报、近 7 天、近 14 天、活动周期等场景,因为日期条件不需要随着每个目标 ID 一遍又一遍参与完整汇总。

七、为什么这种结构通常更适合大数据报表

不需要编造“快 3 倍”“快 10 倍”这种没有测试环境支撑的数字。真正的区别看计算结构就够了。

SUMIFS 模式

目标 1 → 针对源数据计算条件汇总
目标 2 → 再计算一次条件汇总
目标 3 → 再计算一次条件汇总
目标 4 → 再计算一次条件汇总
……

源数据越大、目标越多,重复工作越容易累积。

GROUPBY + XLOOKUP 模式

源数据

集中汇总一次

生成较小的唯一 Key 汇总表

所有目标去汇总表 XLOOKUP

这里真正的优化点是:

把“很多目标分别做汇总”,改成“源表统一做一次汇总”。

GROUPBY 只是刚好很适合承担“集中汇总”这一步,XLOOKUP 则负责把结果映射回目标表。

因此不要机械理解成:

GROUPBY 比 SUMIFS 高级,所以一定更快。

正确理解应该是:

当同一份源数据需要被大量重复汇总时,先 GROUPBY 压缩结果,再 XLOOKUP 查回,通常更值得考虑。

小数据里,两者差异可能完全感觉不到;甚至一条简单的 SUMIFS 反而更直观。公式优化也要看实际计算形状,而不是追求“新函数”。

八、什么时候该换?直接看这张表

场景推荐
源数据几百行、查询很少SUMIFSGROUPBY + XLOOKUP 都可以,优先可读性
数据几千行,但大量公式反复汇总同一个源表倾向 GROUPBY + XLOOKUP
几万~几十万行订单数据,且目标查询很多优先考虑 GROUPBY + XLOOKUP
Key 已经唯一,不需要汇总直接 XLOOKUP
需要先筛日期范围再汇总FILTER + GROUPBY + XLOOKUP
多条件汇总组合 Key + GROUPBY + XLOOKUP

还有一个很实用的判断方法:

如果你发现自己正在同一个 Sheet 里写很多列 SUMIFS,而这些公式反复读取同一张订单明细,只是目标 Key 不同,就值得停下来看看能不能先生成一次汇总结果。

九、最终记住的不是公式,而是这条数据流

这篇文章最值得带走的,不是某一条很长的 LET 公式,而是一个报表计算习惯:

01先缩小数据需要日期条件就先 FILTER
02集中汇总GROUPBY 只做一次
03批量映射XLOOKUP 查回目标表

以后再遇到:

“按 Key 汇总源数据,再把结果填回目标表”

先别急着继续复制 SUMIFS

可以先问一句:

这份源数据,能不能先汇总一次?

如果答案是可以,那么 GROUPBY + XLOOKUP 往往就是一条更适合大型动态报表的计算路径。