Содержание:
Один из ключевых способов ускорить выполнение кода – минимизировать количество запросов к базе данных. Например, вместо использования нескольких SOQL-запросов внутри цикла, соберите все необходимые данные в одном запросе. Это снизит нагрузку на систему и сократит время выполнения. Для этого используйте Map или Set, чтобы организовать данные и избежать дублирования.
Еще один важный аспект – работа с триггерами. Избегайте выполнения сложной логики внутри триггеров. Лучше перенести её в отдельные классы, используя паттерн Trigger Handler. Это не только упростит поддержку кода, но и позволит избежать ошибок, связанных с повторным вызовом триггеров.
Для работы с большими объемами данных используйте Batch Apex. Этот подход позволяет обрабатывать записи порциями, что предотвращает превышение лимитов по памяти и времени выполнения. Убедитесь, что ваш класс реализует интерфейс Database.Batchable и корректно обрабатывает ошибки в методе execute.
Не забывайте о тестировании. Напишите юнит-тесты, которые покрывают не менее 75% кода. Это не только обеспечит выполнение требований платформы, но и поможет выявить узкие места в производительности. Используйте Test.startTest и Test.stopTest, чтобы измерить время выполнения и убедиться, что код работает в рамках лимитов.
Улучшение производительности кода
Используйте пакетную обработку данных для снижения нагрузки на сервер. Например, при работе с большими объемами информации разбивайте операции на части, обрабатывая их в цикле с ограничением в 200 записей за один вызов. Это предотвратит превышение лимитов и ускорит выполнение.
Сокращение количества SOQL-запросов
Минимизируйте количество запросов к базе данных, объединяя их в один, если это возможно. Вместо нескольких отдельных SOQL-запросов используйте вложенные запросы или агрегатные функции. Например, для подсчета связанных записей применяйте COUNT() в одном запросе.
Пример:
SELECT Id, (SELECT Id FROM Contacts) FROM Account
Оптимизация циклов и условий
Избегайте вложенных циклов, особенно при работе с коллекциями. Используйте Map для быстрого доступа к данным. Например, создайте Map с ключом по Id, чтобы избежать повторного поиска в списке.
Пример:
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
Проверяйте условия до выполнения операций. Например, перед обновлением списка убедитесь, что он не пуст:
if (!records.isEmpty()) {
update records;
}
Используйте Switch вместо множественных if-else, если это упрощает логику и повышает читаемость.
Сокращение количества SOQL-запросов в цикле
Избегайте выполнения SOQL-запросов внутри циклов. Вместо этого соберите необходимые данные заранее, используя коллекции. Например, если вам нужно получить данные для списка идентификаторов, выполните один запрос с условием IN и сохраните результаты в Map.
Пример:
Set<Id> accountIds = new Set<Id>();
for (Opportunity opp : opportunities) {
accountIds.add(opp.AccountId);
}
Map<Id, Account> accountMap = new Map<Id, Account>([
SELECT Id, Name FROM Account WHERE Id IN :accountIds
]);
for (Opportunity opp : opportunities) {
Account acc = accountMap.get(opp.AccountId);
if (acc != null) {
// Используйте данные из accountMap
}
}
Используйте агрегатные запросы для получения данных, которые требуют подсчета или группировки. Это позволяет избежать множественных запросов и уменьшает нагрузку на систему.
Пример:
AggregateResult[] groupedResults = [
SELECT AccountId, COUNT(Id) total FROM Opportunity
GROUP BY AccountId
];
for (AggregateResult ar : groupedResults) {
Id accountId = (Id)ar.get('AccountId');
Integer total = (Integer)ar.get('total');
// Обработка данных
}
Если данные требуют сложной обработки, рассмотрите использование пакетных классов. Это позволяет разделить нагрузку и избежать превышения лимитов.
Проверяйте наличие данных перед выполнением запросов. Например, если список идентификаторов пуст, запрос не должен выполняться.
Пример:
if (!accountIds.isEmpty()) {
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
}
Используйте кеширование данных, если они не изменяются в течение выполнения транзакции. Это особенно полезно для статических данных, таких как справочники.
Оптимизация работы с триггерами: избежание рекурсии и дублирования логики
Используйте статические переменные для предотвращения рекурсии. Например, создайте статический флаг, который будет блокировать повторный вызов триггера в рамках одного контекста выполнения. Пример:
public class TriggerHandler {
public static Boolean isFirstRun = true;
}
trigger AccountTrigger on Account (before update) {
if (TriggerHandler.isFirstRun) {
TriggerHandler.isFirstRun = false;
// Ваша логика
}
}
Разделяйте логику на отдельные классы, чтобы избежать дублирования кода. Создайте класс-обработчик, который будет содержать всю бизнес-логику, и вызывайте его из триггера. Это упростит поддержку и тестирование.
public class AccountHandler {
public static void handleBeforeUpdate(List<Account> accounts) {
// Логика обработки
}
}
trigger AccountTrigger on Account (before update) {
AccountHandler.handleBeforeUpdate(Trigger.new);
}
Используйте контекстные переменные триггера (Trigger.isBefore, Trigger.isAfter и т.д.) для четкого разделения логики в зависимости от этапа выполнения. Это предотвратит выполнение ненужных операций.
trigger AccountTrigger on Account (before update, after update) {
if (Trigger.isBefore) {
// Логика для before update
} else if (Trigger.isAfter) {
// Логика для after update
}
}
Минимизируйте количество SOQL-запросов и DML-операций внутри триггеров. Используйте коллекции и массовые операции для обработки данных. Например, собирайте все необходимые Id в Set и выполняйте один запрос.
trigger ContactTrigger on Contact (after update) {
Set<Id> accountIds = new Set<Id>();
for (Contact con : Trigger.new) {
accountIds.add(con.AccountId);
}
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
// Дальнейшая обработка
}
Проверяйте изменения полей перед выполнением логики. Это снизит нагрузку и предотвратит ненужные операции. Используйте метод Trigger.oldMap для сравнения старых и новых значений.
trigger OpportunityTrigger on Opportunity (before update) {
for (Opportunity opp : Trigger.new) {
if (opp.Amount != Trigger.oldMap.get(opp.Id).Amount) {
// Логика, если поле Amount изменилось
}
}
}