Salesforce - Performance analysis of Apex

  It was Diwali festival last weekend and a long weekend for me. During this break, I thought to write a blog on how we can analyse the performance of various Apex properties(Apex Methods, Queries, Workflow, Callouts, DML, validations, Triggers and Pages). 

In your personal or work projects, you may come across the situation where apex code (mostly APIs callout) take time to execute which results in a delay, and eventually a bad user experience👎. Performance analysis is helpful in determining which Apex property is taking much time to load or execute, and accordingly you can make the application more efficient, and eventually improve the customer's interaction with application.

There are many ways of analysing the Apex logs. Some people use VS Code extensions like 'Apex Log Analyzer'. But, I prefer to analyse directly in Developer Console. To keep the blog short and comprehensible, I'll create an LWC application and call the server side Apex methods with delayed execution(to mock delay in server side call).









User🙅- It is taking too much time to load. Not a good app.

Client🙍 - Why is it taking too much time?

Developer 🤔- Where is it taking so much time to execute and load the data??


First of all, let’s define the Apex file. The code is simple-

public class ExecutionDelay {
   
    @auraenabled
    public static string delayExecution(){
        return delayExecution1Sec();
    }
   
    public static string delayExecution1Sec(){
        Datetime date_time=System.now().addSeconds(1);
        while(System.now()<date_time){
            //Executes in 1+2+3=6 secs
        }
        return delayExecution2Secs();
    }
   
    public static string delayExecution2Secs(){
        Datetime date_time=System.now().addSeconds(2);
        while(System.now()<date_time){
            //Executes in 2+3=5 secs
        }
        return delayExecution3Secs();
    }
   
    public static string delayExecution3Secs(){
        Datetime date_time=System.now().addSeconds(3);
        while(System.now()<date_time){
            //Executes in 3 secs
        }
        return 'Completed the Execution';
    }
}

Note - If you are interested to see LWC code as well, I have attached it at the end of this blog.

I am chaining the apex methods calling such that delayExecution() calls delayExecution1Sec() which executes for 1 sec and further calls delayExecution2Secs() which executes for 2 secs and end up calling delayExecution3Secs() which executes for 3 secs.

delayExecution()delayExecution1Sec()⇒⇒⇒delayExecution2Secs()⇒⇒delayExecution3Secs()

Lets Execute and analyse the code📝

1. After click on 'Start the apex execution' button on LWC, It calls the apex class 'Execution Delay' and generates the log file in Developer Console-





 







2. Now, Open the log.
3. Go to 'Debug'>'Switch Perspective' and Select 'Analysis(Predefined)'

















You will see the detailed execution window. I'll not go in detail for all the sections. For this blog, Execution Overview section is important to me, particularly 'Timeline' & 'Executed units' tabs.


Timeline- shows the time taken in ms and % of total time taken by apex properties.
Executed units- shows the detailed view of execution including the filters, name, time taken, heap size etc.


4. Timeline tab shows Apex code took aprox 6 secs 😱 to execute and consumed 100% time.
(let’s hope that your real Apex or API does not take that long to be executed! 😅)

















Likewise, time taken by individual component(Api callout, validation, DB etc) to execute can be analysed.













5. In 'Executed units' tab, we can filter out the executed data based on apex properties. In our case, It is just 'Method' filter that we need to use.

6. Sort the heap size in ascending order.

You can clearly observe the time taken by individual method with the below calculation-








Once we know which part of code is taking time in execution, then we can do an improvisation by following the Salesforce best practices -


I hope this blog post helps you when facing a situation like this in your personal or work projects. If you have any questions or something to add to it, just leave a comment and I will be happy to reply.



LWC Reference code-

.html-

<template>
    <template if:true={isLoading}>
        <lightning-spinner size="large"></lightning-spinner>
    </template>
    <lightning-card title="Analyse the perfomance" icon-name="action:new_note">
        <lightning-layout multiple-rows>
            <lightning-layout-item size="12" padding="around-medium">
                <lightning-button label="Start the apex execution" onclick={handleClick} variant="brand">
                </lightning-button>
            </lightning-layout-item>
            <lightning-layout-item size="12" padding="around-medium">
                <div class="slds-text-heading_medium">{displayStatus}</div>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>


.js-

import { LightningElement } from 'lwc';
import delayExecution from '@salesforce/apex/ExecutionDelay.delayExecution';
export default class PerformanceAnalysis extends LightningElement {

    displayStatus;
    isLoading=false;

    handleClick(){
        this.isLoading=true;
        delayExecution()
        .then((response)=>{  
            this.displayStatus=response;
            this.isLoading=false;
        }).catch((error) => {
            console.log(error);
            this.isLoading=false;
        });
    }    
}


.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
    <target>lightning__AppPage</target>
    <target>lightning__HomePage</target>
    <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

Comments

Popular posts from this blog

Apex - Enforcing Sharing Rules