Integrate CMS Content Into Lightning Communities with CMS Connect
Performance Tuning for Visualforce and Apex
1. Performance Tuning for Visualforce
and Apex
Stuart Bernstein
ISV Technical Evangelist
Thomas Harris
LMTS, CCE Production Support
John Tan
SMTS, CCE Technical Enablement
2. Safe Harbor
Safe harbor statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties
materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results
expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be
deemed forward-looking, including any projections of product or service availability, subscriber growth, earnings, revenues, or other
financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any
statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new
functionality for our service, new products and services, our new business model, our past operating losses, possible fluctuations in our
operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of
intellectual property and other litigation, risks associated with possible mergers and acquisitions, the immature market in which we
operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new
releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization
and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of
salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This
documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of
our Web site.
Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently
available and may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based
upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-
looking statements.
4. Stuart Bernstein
ISV Technical Evangelist
Thomas Harris
LMTS, CCE Production Support
John Tan
SMTS, CCE Technical Enablement
5. Introduction
This session is designed to help with common Visualforce/Apex
performance issues targeted towards intermediate/advanced
Force.com developers.
7. You Need to Build ON A Solid Foundation
Follow SOQL Best practices
Then tune Apex
Then tune Visualforce
8. Indexes Are Vital for Well-performing SOQL
Without an index the SOQL query may not perform well
Standard indexes already exist on Record_Type_Id, Division,
Created_Date, System_Modstamp (Last_Modified_Date),
Name, Email (for Contacts and Leads), and the unique
Salesforce record ID (Foreign Keys)
10. Need Additional Indexes?
Salesforce support can create single and two-column custom indexes
on most fields (with the exception of multi-picklists, formula fields that
reference other objects, and Long Text Area/Rich Text Area)
Open a case
- Sample Query
- Bind Variables
- Org ID and user ID who would run the query
- Suggested index - OPTIONAL
If they create an index, then SAVE and document where the index
was created
11. Will an Index Be Used?
• Whether an index is used is based on the expected number of
records that will be returned.
• A standard index will generally be used:
• If the filter matches less than 30% of the total records, up to 1M records.
• A custom index will generally be used:
• If the filter matches less than 10% of the total records, up to 333K
records.
• OR conditions require that all columns be indexed
12. Use a Standard Index
Select name from account where Id=‘00530000003hQLJ’
Performs quickly because ID is an standard index
13. Use a Custom Index
Select name from account where
SLA_Serial_Number__c=‘1234567’
Performs quickly because SLA_Serial_Number__c is a custom
index
14. Use a Custom Index
Select name from account where SLA_Serial_Number__c=‘’
Doesn’t work because null prevents the index from being used.
15. Use a Custom Index
Select name from account where SLA_Serial_Number__c IN
:ListOfSerialNums
May work well
if no null variable in ListOfSerialNums
filter matches less than 10% of the total records up to 333,000 records
30% of the total records up to one million records if this was a standard index
(it’s not)
16. Don’t Use NOT IN
Select name from account where SLA_Status__C NOT IN (‘Valid’)
NOT IN also prevents the index from being used
17. One (best) Index Will Be Used
Select name from account where SLA_Status__C NOT IN
(‘Processed’) AND SLA_Serial_Number__c=‘1234567’
If one index is not usable, then the best remaining index will be
used.
18. One (best) Index Will Be Used
Select name from account where SLA_Status__C IN
(‘Processed’) AND SLA_Serial_Number__c=‘1234567’
If all indexes are usable, the best index will be used.
19. Cross-object Formula Fields Can Prevent Index
Usage
Contact.SLA_Formula__c is a formula field that copies the value
in Account.SLA_Serial_Number__c.
Select name from contact where SLA_Formula__c IN
:ListOfSerialNums
A custom index on Account.SLA_Serial_Number__c cannot be used
in this query.
Use this query instead, where the index can be used:
Select name from contact where Account.SLA_Serial_Number__c IN
:ListOfSerialNums
20. Denormalizing Data Increases Performance
Select name from contact where Account.SLA_Serial_Number__c
IN :ListOfSerialNums
Solution
Copy SLA_Serial_Number to a field in Contact (don’t use a
formula) and make the field an External Id
OR query for the account IDs with the SLA Serial number first
21. Query Only The Necessary Fields
SELECT
AccountNumber,AccountSource,Active__c,AnnualRevenue,BillingCity,BillingCountry,BillingPo
stalCode,BillingState,BillingStreet,CreatedById,CreatedDate,CustomerPriority__c,Description,
Fax,Id,Industry,IsDeleted,Jigsaw,JigsawCompanyId,LastActivityDate,LastModifiedById,LastM
odifiedDate,MasterRecordId,Name,NumberOfEmployees,NumberofLocations__c,OwnerId,O
wnership,ParentId,Phone,Rating,ShippingCity,ShippingCountry,ShippingPostalCode,Shipping
State,ShippingStreet,Sic,SicDesc,Site,SLAExpirationDate__c,SLA_Serial_Number__c,SLA__
c,SystemModstamp,TickerSymbol,Type,UpsellOpportunity__c,Website FROM Account
22. SOSL Performance Best Practices
SOSL queries for the data using a different technique but then
takes the data and adds the where clause using SOQL
- Eg FIND {foo} RETURNING Account (Id WHERE City='Rome') is
analogous to SELECT Id FROM Account WHERE ID IN (<list of Ids
from search>) AND City='Rome’
Follow SOQL best practices for the where clause
23. Batch Apex
Most common issue is performance of SOQL used in the start()
method.
Avoid the use of non-selective filters in the start() method.
- Queries will perform significantly worse as more data is added.
Don’t add a non-selective filter to filter out a few rows relative to
the overall size of the result set. Instead, use Apex to filter out
rows in the execute() method.
24. Batch Apex – Start Method Queries
Suppose you have 5M records in Account. You want to process the
80% of those records represented by this query:
- SELECT Id FROM Account WHERE Rating__c IN ('Excellent','Good','Moderate')
Since there is no way to use a selective filter in a query for these
records, this query will not run quickly even if Rating__c is indexed.
As an alternative, use this query in the start method:
- SELECT Id FROM Account
Filter out the unwanted records in the execute method.
25. Batch Apex – Start Method Queries – Sample Class
global Database.QueryLocator<SObject> start(Database.BatchableContext bc) {
return Database.getQueryLocator('SELECT Id FROM Account');
}
global void execute(Database.BatchableContext bc, List<Account> scope) {
List<Account> actualScope = [SELECT Id, Name, Description FROM Account
WHERE Rating__c IN
('Excellent','Good','Moderate’)
AND Id IN :scope];
for(Account acc : actualScope) { /* do something */ }
}
26. Batch Apex – Avoid Errors in Bulk DML
global void execute(Database.BatchableContext bc, List<Account>
scope) {
for(Account acc : scope) { /* do something */ }
Database.SaveResult[] results = Database.update(scope,
false);
/* look at results */
}
If an error occurs in this save operation, Salesforce will try to save it one
record at a time.
This performs significantly slower than a bulk save without errors.
27. Parent-Child Locking
Insert of Contact requires locking the parent Account.
Insert or Update of Event requires locking both the parent Contact and the
parent Account.
Insert or Update of Task requires locking both the parent Contact and
parent Account, if the Task is marked as complete.
Insert of Case requires locking the parent Contact and parent Account.
In objects that are part of a master/detail relationship, updating a detail
record requires locking the parent if roll-up summary fields exist.
28. Sharing Calculations
“Implicit” Sharing
- Record access built into Salesforce applications
Parent Implicit Sharing (Account only, private sharing model)
- Access to Contact/Opportunity/Case = Read access to parent
account
- not used when sharing on the child is controlled by parent
- when user loses access to a child, need to check all other children
to see if we can delete the parent implicit share
29. Should we delete Jane’s parent implicit share?
Sharing calculations Universal
Containers
impacted by Data Skew
300K unassigned contacts X
under account
Private sharing model ?
Jane has access to contact
Bob Smith
Bob
Smith
Fred
Green
Betty
Brown … 300K
Contact
Jane losses access to contact
Should we delete Jane’s
parent implicit share for X
Universal Containers?
Can’t code around Data Skew
30. Effects of data skew
Sharing calculations run longer
Concurrent Request Limit error
- Synchronous Apex request starts counting against the limit waiting >
5 sec for lock.
UNABLE_TO_LOCK_ROW error
- Timed out waiting 10 seconds to acquire lock.
- Even if no errors occur, waiting for locks can significantly slow DML
operations.
31. Recommendations
Consider a public read/write sharing model
- Parent will still be locked. No sharing calculations.
10K children or less
Prevent parent-child data skews
- Detect whether existing accounts already have "reached their limit"
of child records, and create new accounts.
32. Visualforce – Best Practices
http://developer.force.com/dreamforce/11/session/Blazing-
Fast-Visualforce-Pages
View State
- Filter and Paginate
- Transient keyword
- Simplify component hierarchy
- JavaScript Remoting
33. Analyzing Performance
Measure performance in the browser first to see if the
problem is client-side or server-side.
- Chrome Developer Tools and the Firebug plugin for Firefox will both
work for this.
After confirming the problem is on the server, use the
Salesforce Developer Console to find areas you can tune.
35. Analyzing Performance
In Chrome, press F12 to open Developer Tools.
Use the Network tab to measure performance.
It takes 8.74 seconds to get a response from the server when pressing the “Do BOTH Slow Query and
Callout” button.
36. Analyzing Performance – Developer Console
Use the Developer Console to analyze server-side performance.
Apex debug logs will be generated for every server request you perform
while the window is open.
Several tools are available in the Developer Console to find performance
hotspots.
40. 3) Identify the slow
portion and click on the
bar. This loads the
relevant log lines into
the Execution Log.
41. 4) Click on a line in
the Execution Log to
show the stack trace
for the slow query on
the left.
42. Analyzing Performance – Log Levels
The default log levels generate a huge amount of output, most of which
is unnecessary for debugging performance issues.
This also makes the console slower.
Try lowering the log levels so you can look for slow queries and callouts
first.
43. Analyzing Performance – Heap Dumps
The Developer Console can also be used to create Apex
heaps that help in debugging.
For example, you can use it look at the bind variables for a
query.
45. Analyzing Performance – Heap Dumps
The bind variables will
not show up in the
debug console and may
not be easy to find.
You can set a heap
dump breakpoint to get
the variable values at
the time the query is
run.
47. Analyzing Performance – Heap Dumps
The runtime values
of the variables can
be found in the
Symbols tab of the
heap dump viewer.
48. Analyzing Performance – Useful Tools
Developer Console
Firebug (http://getfirebug.com)
- Web development plugin for Firefox.
Chrome Developer Tools
- Included with Chrome.
Workbench (https://workbench.developerforce.com)
- Good for testing SOQL queries.
Fiddler (http://www.fiddler2.com/fiddler2)
- Windows tool for debugging HTTP traffic, integrates well with IE and Firefox.
49. Working with Support
SOQL performance
- Open a case with org Id, user Id, SOQL and bind variables.
- Can add custom single and two column indexes.
Record locks
- Provide support the org ID and time frame where the issues
occurred.
- Provide the IDs of affected records if possible.
50. Useful Links
Architect Core Resources
http://wiki.developerforce.com/page/Architect_Core_Resources
- Guide to Sharing Architecture
- Record Access: Under the Hood
- Best Practices for Deployments with Large Data Volumes
- Asynchronous Processing in Force.com
- VF Performance
51. Stuart Bernstein Thomas Harris John Tan
ISV Technical Evangelist LMTS, CCE Production SMTS, CCE Technical
Support Enablement