一、先搞懂最容易踩的坑:SharePoint列表的阈值限制
很多人刚开始用SharePoint存数据、再用Power Apps做前端界面的时候,都会碰到一个莫名其妙的报错:要么数据加载不出来,要么筛选时提示“超过最大项数限制”。这背后的核心问题,就是SharePoint列表的阈值限制。
先给大家说清楚这个限制到底是什么:SharePoint默认的列表项阈值是5000项,也就是说,当你的列表里的项数超过5000之后,直接做全量查询、全量排序、或者带复杂条件的筛选时,系统会直接报错,不让你查。这个限制不是Power Apps的问题,是SharePoint本身的性能保护机制——毕竟如果一次查几万条数据,服务器扛不住,整个SharePoint站点都会变慢。
举个最常见的应用场景:比如你公司用SharePoint存所有员工的报销申请,从2022年开始存,到2024年已经有6000条申请记录了。然后你用Power Apps做了一个报销查询界面,想让员工能看到自己所有的报销记录,结果员工一打开界面,直接弹出报错,根本看不到数据。
那这个限制的优缺点是什么呢?优点很明显:能保护SharePoint服务器的性能,不会因为某一个应用的过度查询导致整个站点瘫痪;缺点就是对开发者不友好,很多刚接触的人根本不知道这个限制,碰到报错一脸懵,而且处理不好的话,用户体验会特别差。
注意事项这里要强调:这个阈值是可以在SharePoint管理中心改的,但不建议改!因为改大之后,一旦有人做全量查询,很容易拖垮整个SharePoint站点,影响所有员工的正常使用。所以最好的办法不是改阈值,而是想办法绕过这个限制。
二、突破阈值的核心办法:分页查询
既然不能改阈值,那怎么让Power Apps能正常加载超过5000项的SharePoint列表数据呢?答案就是分页查询。
分页查询的逻辑其实很简单:把一次要查的所有数据,分成很多个小批次,每个批次查的项数都不超过阈值(比如每次查2000项),然后把这些批次的数据拼起来,就是完整的数据了。
这里先给大家明确要用到的技术栈:Power Apps 画布应用 + SharePoint 列表(所有示例都用这个组合,不会混其他技术)。
2.1 先准备一个测试用的SharePoint列表
在写代码之前,我们先建一个测试用的SharePoint列表,方便大家跟着操作。打开SharePoint,新建一个列表,名字叫“报销申请”,然后添加两个列:
- 员工姓名:文本类型
- 申请日期:日期类型
然后我们往这个列表里加6000条测试数据(可以用批量导入的方式,比如先在Excel里做好6000条数据,再导入到SharePoint列表里),这样就能触发阈值限制了。
2.2 Power Apps里的分页查询实现
接下来我们就在Power Apps的画布应用里写代码,实现分页查询。首先,我们需要在Power Apps里做两个变量:
- pageSize:每一页要查的项数,我们设为2000(比5000小,不会触发阈值)
- currentPage:当前要查的页码,初始值为1
然后我们写一个自定义函数,用来获取指定页码的数据。自定义函数的写法是在Power Apps的“公式栏”里输入,具体代码如下:
// 自定义函数:GetPageData,参数是要查询的页码
GetPageData = (page: Number) =>
// 先计算要跳过的项数:(页码-1)*每页项数
With(
{skipCount: (page - 1) * pageSize},
// 用SharePoint的Sort函数排序,用Skip函数跳过前面的项,用Take函数取当前页的项
Sort(
Filter('报销申请', 员工姓名 = "张三"), // 这里的筛选条件可以改成你自己的,比如筛选特定员工的申请
申请日期,
Descending
)
|> Skip(skipCount)
|> Take(pageSize)
);
给大家解释一下这段代码的意思:首先,我们用With函数定义了一个变量skipCount,用来计算当前页之前有多少项数据,比如第一页的skipCount是0,第二页是2000,第三页是4000,以此类推。然后我们用Sort函数对“报销申请”列表按申请日期降序排序,再用Skip函数跳过前面的skipCount项,最后用Take函数取pageSize项,也就是当前页的2000项。
这里要注意一个关键点:Sort函数必须用在Filter函数之后,而且Sort的列必须是SharePoint列表里已经建了索引的列。为什么呢?因为SharePoint的阈值限制有个小规则:如果你的查询是对有索引的列做排序或者筛选,那么就算项数超过5000,只要你取的项数不超过阈值,就不会报错。所以我们要给“申请日期”列建索引,步骤是:打开SharePoint的“报销申请”列表,点击“设置”->“列表设置”->“索引列”->“新建索引”,然后选择“申请日期”作为索引列,保存就可以了。
2.3 把多页数据拼起来
刚才的函数只能获取单页的数据,那怎么把所有页的数据拼起来呢?我们可以再写一个自定义函数,用来获取所有页的数据:
// 自定义函数:GetAllData,用来获取所有符合条件的数据
GetAllData = () =>
// 先计算总共有多少页:总项数除以每页项数,向上取整
With(
{
// 先获取符合条件的总项数,这里用CountRows函数,因为我们的筛选是对有索引的列,所以不会触发阈值
totalCount: CountRows(Filter('报销申请', 员工姓名 = "张三")),
// 计算总页数:总项数除以每页项数,向上取整
totalPages: RoundUp(totalCount / pageSize, 0)
},
// 循环获取每一页的数据,然后拼起来
ForAll(
Sequence(totalPages), // 生成一个从1到totalPages的序列
GetPageData(Value) // 获取每一页的数据
)
|> Ungroup(Value, "Value") // 把所有页的数组合并成一个大数组
);
这段代码的逻辑是:首先用CountRows函数获取符合条件的总项数,然后计算总页数。接着用ForAll函数循环每一页,获取每一页的数据,最后用Ungroup函数把所有页的数组合并成一个完整的数组。
这里要注意CountRows函数的使用:CountRows函数是用来计算符合条件的项数的,只有当你的筛选条件是对有索引的列时,CountRows函数才不会触发阈值限制。所以我们之前给“申请日期”建索引是很有必要的。
2.4 测试代码
现在我们来测试一下这段代码。在Power Apps的画布应用里,添加一个“集合”控件,然后在“OnVisible”属性里输入:
ClearCollect(AllExpenses, GetAllData());
然后运行应用,查看AllExpenses集合里的数据,你会发现所有符合条件的报销申请都加载出来了,不会再触发阈值限制的报错。
三、分页查询的优化方案
刚才的分页查询虽然能解决问题,但还有可以优化的地方,比如性能和用户体验。
3.1 延迟加载优化
如果你的数据量特别大,比如有几万条,一次性获取所有页的数据会很慢,用户打开应用的时候会等很久。这时候可以用延迟加载的方案:一开始只加载第一页的数据,当用户点击“下一页”的时候,再加载下一页的数据。
具体实现方法是:在Power Apps的界面上添加“上一页”和“下一页”按钮,然后在“下一页”按钮的“OnSelect”属性里输入:
Set(currentPage, currentPage + 1);
ClearCollect(CurrentPageData, GetPageData(currentPage));
在“上一页”按钮的“OnSelect”属性里输入:
Set(currentPage, currentPage - 1);
ClearCollect(CurrentPageData, GetPageData(currentPage));
然后把界面上的表格绑定到CurrentPageData集合,这样用户打开应用的时候只会加载第一页的数据,点击下一页的时候再加载下一页,速度会快很多。
3.2 筛选条件优化
如果你的筛选条件比较复杂,比如要同时筛选员工姓名和申请日期,那你需要给这两个列都建索引吗?其实不用,只要给筛选条件里的列建索引就可以了。比如你的筛选条件是“员工姓名 = "张三" And 申请日期 >= Date(2023,1,1)”,那你需要给“员工姓名”和“申请日期”都建索引吗?其实只要给“员工姓名”建索引就可以了,因为SharePoint会优先用“员工姓名”这个索引来筛选,然后再对筛选出来的结果按申请日期排序。
不过这里要注意:如果你的筛选条件里有两个以上的列,最好给所有筛选列都建索引,这样查询速度会更快。
四、方案的优缺点和注意事项
4.1 方案的优缺点
优点:
- 不用修改SharePoint的阈值限制,不会影响整个站点的性能;
- 实现简单,只需要在Power Apps里写几行代码就可以;
- 可以灵活调整每页的项数,比如数据量小的时候可以设为1000,数据量大的时候可以设为2000;
- 可以优化用户体验,比如用延迟加载的方式,让用户不用等太久就能看到数据。
缺点:
- 如果数据量特别大,一次性获取所有页的数据还是会比较慢;
- 代码里的筛选条件如果写得不好,还是有可能触发阈值限制;
- 索引列的数量是有限制的,SharePoint列表最多只能建20个索引列,所以不能给所有列都建索引。
4.2 注意事项
- 一定要给筛选和排序的列建索引,否则分页查询还是会触发阈值限制;
- 每页的项数不要设得太大,比如不要设为4000,最好设为2000以下,这样就算SharePoint的阈值有波动,也不会触发报错;
- 不要用CountRows函数对没有索引的列做筛选,否则会触发阈值限制;
- 测试的时候一定要把SharePoint列表的项数加到超过5000,否则测试不出来阈值限制的问题。
五、应用场景总结
这个分页查询方案适合的应用场景主要有:
- 用SharePoint存历史数据,比如员工报销、客户订单、项目进度等,数据量超过5000项;
- 用Power Apps做前端界面,需要查询超过5000项的SharePoint列表数据;
- 不能修改SharePoint的阈值限制,比如SharePoint站点是公司统一管理的,没有权限修改阈值;
- 需要灵活筛选和排序数据,比如按时间、按部门、按员工筛选数据。
这个方案不适合的应用场景主要有:
- 数据量特别大,比如超过10万项,这时候最好用专门的数据库,比如SQL Server,而不是SharePoint;
- 需要实时更新大量数据,比如每秒都要更新几千条数据,这时候SharePoint的性能跟不上;
- 需要复杂的数据分析,比如数据挖掘、机器学习等,这时候SharePoint的功能不够用。
评论
围绕“SharePoint列表项与Power Apps集成陷阱:阈值限制突破与分页方案”参与讨论