salesforce零基礎學習(一百零二)Limitation篇之 CPU Limit

zero.zhang發表於2021-03-26

本篇參考:

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的描述。篇中有錯誤歡迎指出,有不懂歡迎留言。

相關文章