Expensive describe or metadata call inside a loop

ID

apex.performance.high_cost_in_loop

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Performance

Language

Apex

Description

Reports a schema describe call, a Limits reading or an email send written inside a for or while loop.

Rationale

Schema.getGlobalDescribe() builds a map of every object in the org - a call measured in hundreds of milliseconds on a large org - and it returns the same map every time. Calling it per iteration multiplies that cost by the batch size and spends the transaction’s ten-second CPU budget on work whose result never changes. Messaging.sendEmail in a loop is the same shape against a much harder limit: ten email invocations per transaction.

The following code illustrates the pattern detected by this rule:

public class DescribeUsage {

    public void perRecord(List<Account> accts) {
        for (Account a : accts) {
            // FLAGGED: Expensive describe or metadata call inside a loop
            Map<String, Schema.SObjectType> types = Schema.getGlobalDescribe();
            // FLAGGED: Expensive describe or metadata call inside a loop
            Messaging.sendEmail(new List<Messaging.SingleEmailMessage>());
            System.debug(types.size());
        }
    }

    public void perIterationReceiver(List<Schema.SObjectField> fields) {
        for (Schema.SObjectField f : fields) {
            Schema.DescribeFieldResult dfr = f.getDescribe();
            System.debug(LoggingLevel.FINE, dfr.getLabel());
        }
    }

    public void hoisted(List<Account> accts) {
        Map<String, Schema.SObjectType> types = Schema.getGlobalDescribe();
        List<Messaging.SingleEmailMessage> messages = new List<Messaging.SingleEmailMessage>();
        for (Account a : accts) {
            System.debug(types.size());
        }
        Messaging.sendEmail(messages);
    }
}

Remediation

Hoist the describe call above the loop and reuse the result, or use the narrower SObjectType.getDescribe() for the one object you need. Collect emails into a List<Messaging.SingleEmailMessage> and send them in a single Messaging.sendEmail call after the loop.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved