数据源慢?服务器性能不够?
为什么你的报表刷新巨慢,可能是你没搞懂查询折叠
✦ 本期核心问题
不是数据源慢,是你把1200万行全拉到本地算。
小李负责的销售日报,每天早上8:30自动刷新。三个月前只要40秒。现在6分12秒。
他找IT。IT看了下服务器:「SQL Server资源使用率不到15%,不是我们这边的问题。」
他找DBA。DBA跑了一下SQL Profiler,截图发过来:「你的Power BI在跑一条 SELECT * FROM SalesOrder,扫了全表1200万行。数据库不慢,是你每次刷新都在把整张表搬进Power BI。」
小李打开Power Query编辑器,点开「销售订单」查询,数了一下:22个应用步骤。筛选、去重、分组、合并、加自定义列、改数据类型……每一步他都觉得「必须做」。
问题就出在这里。不是数据库慢,是数据根本没在数据库里算。
Power Query连接SQL Server这类数据源时,有一个机制叫查询折叠。
简单说:你把M语言写的转换步骤——筛选行、选择列、分组聚合、排序——Power Query把它翻译成一条SQL语句,直接发给数据库执行。数据库算完,只把结果返回给你。
折叠时:1200万行筛选到30万行 → 数据库干,传30万行过来。 ✅
但如果折叠断了呢?Power Query会把1200万行全拉进本地内存,然后用自己的引擎一条条筛。1200万行全部走网卡、进内存、被Mashup引擎处理。
这就是阿豪的6分钟从哪来的。
不是数据库慢,是数据根本没在数据库里算。
查询折叠的规则很残酷:一旦某一步不可折叠,它后面的所有步骤——哪怕本身可以折叠——也都废了。整条链从那个断点开始,全部在本地执行。
小李打开查询折叠指示器(Power Query编辑器 → 视图 → 勾选「查询折叠指示器」),看到:
| 步骤 | 折叠状态 |
|---|---|
| 导航 | 已折叠 |
| 删除其他列 | 已折叠 |
| 筛选日期 ≥ 2026-01-01 | 已折叠 |
| 添加自定义列(提取月份) | 未折叠 |
| 筛选金额 > 1000 | 未折叠 |
| 分组汇总 | 未折叠 |
| …后续所有步骤 | 全部未折叠 |
踩坑提示
断点在第4步:他加了一个自定义列 Month = Date.Month([OrderDate])。这个M函数没有SQL等价物,折叠断了。从这一步开始,后面所有的筛选、分组、去重——全是Power BI在本地吭哧吭哧算。
SQL Server收到的实际查询是什么?DBA截到的就是那条:
前3步折叠成了WHERE条件。第4步一断,第5步的 金额 > 1000 根本没进SQL——它是Power BI把全部数据拉到本地之后才筛的。
小李做了三件事:
他原本的步骤顺序:
调整后:
金额筛选和分组现在排在自定义列前面。SQL Server收到的查询变成了:
结果:数据库先筛再分组,返回的结果集只有2万行。自定义列在2万行上做,毫秒级。
他原来写 Date.Month([OrderDate]) 是为了在报表里按月筛选。这个需求完全可以在数据源端解决:
Power Query直接连视图,OrderMonth 是一个普通整数列,折叠不受影响。
小李还有一个步骤是 Table.AddColumn 用了一串嵌套if做客户分级。这玩意在Power Query里不可折叠,但用SQL的 CASE WHEN 写完全没问题。他在视图里加了这个字段,Power Query只负责拉现成数据。
修完后,他重新看折叠指示器:
| 步骤 | 折叠状态 |
|---|---|
| 导航 | 已折叠 |
| 删除其他列 | 已折叠 |
| 筛选日期 ≥ 2026-01-01 | 已折叠 |
| 筛选金额 > 1000 | 已折叠 |
| 分组汇总 | 已折叠 |
| 添加自定义列(从视图取) | 已折叠 |
全绿。
第二天早上8:30,刷新用了51秒。
小李的问题不是技术不行,是他把Power Query当成ETL工具在用。
Power Query的定位是数据接入层——把数据从源系统接进来、做必要的列筛选和简单转换。不是让你在1200万行上做字符串拼接、日期运算、嵌套条件判断。
一个简单的判断标准:步骤超过15步 + 3个以上自定义列 = 折叠大概率已断。
把复杂计算推回数据源。SQL视图、存储过程、甚至直接在数据库里加计算列——任何你能在数据源端完成的事情,都比在Power Query里做强一百倍。
现在就打开你的Power BI Desktop,做三件事:
1、 启用折叠指示器。文件 → 选项和设置 → 选项 → Power Query编辑器 → 勾选「查询折叠指示器」。然后打开Power Query,看每个查询最后一步的图标颜色。
2、 找到第一个红色步骤。它就是你的断点。看它是什么操作——自定义列?日期函数?文本处理?把能折叠的步骤移到它前面。
3、 右键最后一步,看「查看原生查询」是灰色还是可用。灰色 = 整条链都没折叠。可用 = 至少最后一步之前都在折叠。点开看看SQL长什么样——如果是一个简单的 SELECT * 没带WHERE,说明你的筛选根本没进数据库。
查询折叠不是优化技巧,是Power Query连接关系型数据库的基本工作方式。折叠断了,就等于你主动选择了「把所有数据拉到本地再算」。
这句话值6分钟——报表的6分钟。