salesforce零基础学习(一百零二)Limitation篇之 CPU Limit

本篇参考:

https://help.salesforce.com/articleView?id=000339361&type=1&mode=1

https://developer.salesforce.com/wiki/apex_code_best_practices

https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_apexgov.htm

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_transaction.htm

背景

还记得前几年刚开始接触sf的时候,对标准的功能一点都不懂,因为从java转过来,侧重点大部分在开发上面。所以连Account那些基本表都不清楚,sales cloud等更没有概念。好在那时候经常看apex开发文档,所以开发入手特别快。
转眼都已经做sf 5年多了,回首一下以前的博客,大部分都是某个特定case的实现方式,一些新知识的探索,但是一直没有涉足过apex government limitation的,这些在最开始的开发时很多概念很模糊,很不懂,所以未来几篇侧重点在limitation的介绍上,以便新人可以更好的理解这些,老人也重(同样)温(恶补)一下。最开始做sf classic的开发时,工作多年的大拿很少没有不处理过 cpu limit / heap size limit等等各种各样的问题,本篇先以CPU limitation开始,后续其他的主要的争取都简单介绍,温故而知新,保证开发动手以前可以先多多的思考。
话不多说,今天主要讲两个内容。 Transcation & CPU Limitation

一. Transcation

我们经常会听到前辈们给新人讲salesforce相关的 limitation。一个transcation中SOQL查询回来的数量最多50000条啊,DML最多10000条啊等等。新人肯定很努力的记住相关的关键字, SOQL 搜索50000,DML 10000。 且慢,还有一个关键点,transcation是什么?作为新人真的理解吗?

我们严格的说 transcation的时候,前面都会加 apex transcation,即用apex写代码的时候,才涉及到transcation的概念。比如某些公司前后端分离,你做纯粹的 aura / lwc前端,不需要考虑后端的小伙伴,肯定会想, transcation?excuse me?

是的,transcation的概念只有在apex上下文的情况下才会有这个概念,下文中出现的【transcation】和【事务】是同一个东西,在这里进行说明一下。transcation是什么先卖个关子,先说一下他具有什么特性呢?
transcation有一个主要的特性:transcation中的所有DML操作要么成功完成,要么在一个操作中发生错误,整个事务被回滚,没有数据提交到数据库,当然这种处理我们通常使用 Database.savePoint以及rollback去处理代码逻辑。
既然大前提是apex上下文,所以我们思考一下,我们平时写apex的代码都会有哪些场景?
trigger / apex class / 匿名块 / vf page调用 / web service,如果不全欢迎补充,所有上述的这些可以理解成 transcation的边界,即事务的边界,我们在事务边界内发生的所有操作都表示单个操作单元。
这个时候引出一下官方对transcation的定义:表示作为单个单元执行的一组操作。即上述事务边界执行的所有的操作。

所以我们思考一个场景,我们一个匿名块里面调用了一个类的静态方法,这个静态方法做了一个表的DML操作,这个表同时还有 validation rule / trigger 巴拉巴拉很多操作。当调用了这个方法,执行了DML操作,这个数据最终 commit并且这个静态方法完全执行完,然后最终这个匿名块的所有的逻辑全执行完才算做当前的一个事务结束,这样是否会好点理解呢?

二. CPU Limitation

一个transcation情况下,同步场景10s,异步场景60s。限制是死的不用太纠结,我们只需要知道,哪些会被计入CPU limitation,哪些不会被计入即可。

会被记入的有以下情况:

  • 所有的apex代码
  • apex公开的所有的资源库里面的函数
  • workflow的执行

不会被计入的有以下的情况:

  • 数据库操作。比如花费在DML/SOQL/SOSL的时间就不会被计入进去
  • apex callout等待时间也不会被算进去

所以既然我们知道了哪些场景会被记入,哪些不会被记入,如果真涉及到CPU 调优的场景,尽可能的往以下的场景去优化。官方给了几个场景的sample:

1. Using Map based query:这种场景用于当我们搜索 list出来以后,还需要获取相关的ID作为列表去进行后续操作,官方建议我们别对list for循环继续操作了,通过map去接收,然后使用 keySet以及values去同时获取到id和数据集合。等会还要对它进行引申,先看一下官方的代码。

List<Account> lstacc=[Select Id,Name from Account limit 50000];
Set<Id> setIds=new Set<Id>();
for(Account a:lstacc){ //More CPU time for sure due to looping
setIds.add(a.id);
}

//Using Map query saves CPU time

//Fetching all account in map
Map<id,account> aMap = new Map<id,account>([Select Id,Name from Account limit 50000]);

//Creating list of accounts
List<account> accList = aMap.values() ;

//Creating set of ids

Set<id> accIds = aMap.keySet() ;

2. 如果业务允许的情况下去异步处理,因为异步的CPU limit是60s,时间更充裕。比如部分代码放在 @future里面。但是放在异步的没法保证实时性以及回滚等操作,需要具体业务具体分析,别盲目选择。

3. 业务允许探索一下SOQL聚合的用法,这个很好理解,因为SOQL查询时间不计算在CPU limitation里面。salesforce提供了一些聚合函数等,比如我们场景需要这些,我们可以直接通过SOQL进行聚合,而不是搜索出来以后列表进行处理。

4. 尽量减少不必要的loop操作,如果不可避免,保证数据最少原则,只对需要的数据列表进行操作,从而减少迭代的量,减少CPU使用时间。

看完以后诚惶诚恐的感觉有没有,恨不得想知道我们现有的代码CPU时间用了多少,还有多少时间限制??? apex提供了 Limits这个类来捕捉大部分的government limitation的限制数。比如我们可以通过Limits.getCpuTime()去获取当前时段已经用了多少CPU时间,以ms来计算。
当然,官方推荐的肯定优秀,不代表我们就一定适合当前的场景去进行优化。下面举个例子,希望小伙伴看完拥有自己的思考。我们针对第一个的demo做一下debug,分别打印出来代码执行的CPU limit 以及 heap size limit

第一个代码块

List<Account> lstacc=[Select Id,Name from Account limit 50000];
Set<Id> setIds=new Set<Id>();
for(Account a:lstacc){ //More CPU time for sure due to looping
setIds.add(a.id);
}
system.debug('cpu limit' + Limits.getCpuTime());
system.debug('heap size:' + Limits.getHeapSize());

第二个代码块

//Fetching all account in map
Map<id,account> aMap = new Map<id,account>([Select Id,Name from Account limit 50000]);

//Creating list of accounts
List<account> accList = aMap.values() ;

//Creating set of ids

Set<id> accIds = aMap.keySet() ;
system.debug('cpu limit' + Limits.getCpuTime());
system.debug('heap size:' + Limits.getHeapSize());

执行以后发现了什么???

第一个代码块的CPU时间确实比第二个高,但是相对应的heap size却小一点。

 第二个代码块尽管CPU时间节省了下来,但是因为声明了 map变量, heap size相应的变多了。

 当你在CPU慢慢降下来偷偷窃喜时,也要关注其他的点,因为他们可能在你不注意的时候慢慢的长高了。

salesforce针对apex有好几个government limitation,我们在写代码的时候要从多个角度考虑,好多的点可能是互斥的,我们需要权衡好我们现在要在意什么,可以舍弃什么。空间换时间?时间换空间?没有最好的统一的解决方案,只有最适合你的当前业务场景的某个transcation代码。

总结:篇中根据最上面提供的官方文档进行一下简单的CPU limitation的描述。篇中有错误欢迎指出,有不懂欢迎留言。

posted @ 2021-03-26 12:37  zero.zhang  阅读(966)  评论(0编辑  收藏  举报