Boost Salesforce Query Performance with @ReadOnly for Large Data

Learn how the Apex @ReadOnly annotation unlocks up to 1,000,000-row SOQL queries for read-only operations, where to use it, and its restrictions.

What is the @ReadOnly annotation?

The @ReadOnly annotation in Apex relaxes the standard SOQL row limit (50,000 rows) and allows queries to return up to 1,000,000 rows. It’s designed for scenarios where large volumes of data need to be read without being modified.

Key features and restrictions

  • Increased query limit: Allows up to 1,000,000 rows to be returned by SOQL queries in supported contexts.
  • No DML operations: You cannot insert, update, delete, or undelete records inside a @ReadOnly method.
  • No asynchronous jobs: Calls to System.schedule, Queueable, future, and other enqueued asynchronous Apex are blocked.
  • Limited contexts: Available for REST and SOAP web services and the Schedulable interface (and methods exposed via AuraEnabled/Lightning contexts that are supported).

When to use @ReadOnly

Use @ReadOnly when you need to process or export large datasets and won’t modify the records. Common use cases:

  • Reporting and analytics that require scanning millions of rows
  • Data export for external processing or backups
  • Read-only dashboards and bulk-read endpoints

Example

Simple Apex method using @ReadOnly to return accounts created in the last year:

public with sharing class LargeDataQueryController {
    @AuraEnabled
    @ReadOnly
    public static List getAccounts() {
        // This query will be read-only and optimized for performance
        return [SELECT Id, Name, Industry FROM Account WHERE CreatedDate >= LAST_YEAR];
    }
}

Best practices

  • Keep logic inside @ReadOnly methods strictly read-only; move any updates to separate transactions.
  • Filter queries aggressively (select only required fields, use selective filters) to reduce data transfer and processing costs.
  • Use batch processing or scheduled jobs where appropriate; remember @ReadOnly applies to schedulable contexts too, but still forbids DML within the same method.
  • Monitor performance and governor metrics — reading many rows can still impact execution time and heap usage.

Reference

Salesforce Developer Docs: ReadOnly

Why this matters for Salesforce teams

For admins, developers, and business users, @ReadOnly enables efficient large-scale reads without risking unintended data changes. It’s especially useful for analytics, exports, and integrations where read performance matters more than in-transaction updates.