How to Resolve Too Many Query Rows Error in Salesforce Apex

Being a Salesforce developer , I hope you must have come across the “Too many query rows: 50001” error in Salesforce while working with Apex ,Test class , Flow or handling large data sets. It’s one of those common governor limit errors that every developer runs into at some point mostly in full copy sandbox and production.

Let’s break down in this Salesforcehours article what this error actually means, why Salesforce enforces it, and how you can fix and prevent it in your code going forward.

What is the “Too many query rows: 50001” Error?

This System.LimitException indicates that the total number of records retrieved by all SOQL queries within a single Apex transaction has exceeded the Salesforce platform limit.

Salesforce imposes this limit to ensure fair resource allocation in its multi-tenant environment. Retrieving an excessive number of records consumes significant server memory and processing power, which could negatively impact performance for other users sharing the same resources.

The specific governor limit is:

  • Total number of records retrieved by SOQL queries: 50,000

When your transaction’s cumulative record count from all SOQL queries hits 50,001 or more, Salesforce immediately terminates the transaction and throws this exception.

What Causes the “Too many query rows” Error?

This error typically arises from inefficient SOQL queries that retrieve far more data than necessary or attempt to process large datasets within a single synchronous transaction.

Cause 1: Non-Selective SOQL Queries

The most common cause is writing SOQL queries without sufficiently selective WHERE clauses , LIMIT, especially when querying objects that tend to have a large number of records . So we should always make our Make SOQL query selective

Example:

// ERROR : Querying all Task records without any filter
// In an org with over 50,000 tasks, this will fail.
List<Task> allTasks = [SELECT Id, Subject FROM Task]; 


Cause 2: Querying Large Datasets Synchronously

Attempting to process a very large number of records within a single synchronous context (like a trigger, button click handler, or Visualforce controller action) often leads to this error. Synchronous Apex is not designed for bulk data processing.

Example:

// Trying to process all Accounts in a trigger handler
// If the org has > 50,000 Accounts, this query fails immediately.
List<Account> allAccounts = [SELECT Id, Name, AnnualRevenue FROM Account];
for (Account acc : allAccounts) {
    // Some logic here...
}


Cause 3: Accumulating Rows Across Multiple Queries

Always remember, the limit applies to the total number of rows retrieved across all SOQL queries in the transaction. Even if individual queries retrieve fewer than 50,000 rows, their cumulative total can exceed the limit.

Example:

// Query 1 retrieves 30,000 records
List<Contact> contacts = [SELECT Id FROM Contact WHERE Account.Type = 'Customer']; 

// Query 2 retrieves 25,000 records
List<Lead> leads = [SELECT Id FROM Lead WHERE Status = 'Open']; 

// Total rows = 55,000. The second query will likely cause the exception.


How to Resolve the “Too many query rows” Error

Fixing this error requires optimizing your data retrieval strategy. The goal is to either retrieve fewer records or process large volumes of records in a way that respects the platform limits.

Solution 1: Use Selective WHERE Clauses

This is the most crucial fix. Always filter your SOQL queries to retrieve only the records you actually need. So we should always make our Make SOQL query selective by following Salesforce help article .

  • Filter on Indexed Fields: Use fields that are indexed whenever possible in your WHERE clause (e.g., Id, Name, OwnerId, CreatedDate, External IDs, indexed custom fields). This allows the database to find the relevant records much faster and more efficiently.
  • Be Specific: Make your conditions as specific as possible to narrow down the result set.
  • You can also reach out to Salesforce support to get your custom field indexed to Improve Performance of SOQL Queries

Inefficient Example:

List<Account> accounts = [SELECT Id FROM Account WHERE Name LIKE 'A%']; // Still potentially large


Optimized Example:

// Filter by a specific record type AND an indexed field (OwnerId)
Id specificRecordTypeId = '012.....'; 
List<Account> accounts = [SELECT Id 
                          FROM Account 
                          WHERE RecordTypeId = :specificRecordTypeId 
                          AND OwnerId = :UserInfo.getUserId()]; // Much more selective


Solution 2: Use LIMIT Clauses

If you only need a subset of records or want to explicitly cap the number of records retrieved, use the LIMIT clause. This is often useful for displaying preview data or when you only need some examples, not all records.

Example:

// Retrieve only the 1000 most recent Tasks, not all of them.
List<Task> recentTasks = [SELECT Id, Subject 
                          FROM Task 
                          ORDER BY CreatedDate DESC 
                          LIMIT 1000];


Solution 3: Process Large Datasets Asynchronously with Batch Apex

For use cases that genuinely require processing more than 50,000 records (e.g., nightly data updates, mass calculations), synchronous Apex is not the right tool. You must use Batch Apex.

Batch Apex is specifically designed to process large data volumes by breaking the work into manageable chunks (batches), each with its own set of governor limits, including the 50,000-row query limit. The start method’s Database.QueryLocator can handle querying millions of records without hitting the limit in that initial phase.

Example (Batch Apex Structure):

global class ProcessLargeAccountDataBatch implements Database.Batchable<sObject> {

    global Database.QueryLocator start(Database.BatchableContext BC) {
        // This QueryLocator can handle millions of records without hitting the 50k limit here.
        return Database.getQueryLocator('SELECT Id, Name, AnnualRevenue FROM Account WHERE Needs_Processing__c = true');
    }

    global void execute(Database.BatchableContext BC, List<Account> scope) {
        // 'scope' contains a batch of records (default 200). 
        // Any queries INSIDE execute must respect the 50k limit for THIS batch transaction.
        for (Account acc : scope) {
            // Process each account...
        }
        // update scope; // DML on the batch
    }

    global void finish(Database.BatchableContext BC) {
        // Optional: Send completion email, etc.
    }
}


Solution 4: Optimize Overall Logic

Sometimes, you can restructure your code to avoid querying large numbers of records altogether. Can you achieve the goal by querying fewer, more targeted records? Can you use Aggregate SOQL queries (COUNT(), SUM()) to get summarized data instead of individual rows?

A Simple Demo: From Bug to Fix

Let’s demonstrate the error and a simple fix using the Developer Console.

Scenario: We want to query Task records. In many orgs, the total number of Tasks easily exceeds 50,000.

The Buggy Code (Causes the Error)

// Open Developer Console -> Debug -> Open Execute Anonymous Window
// Run this code. It will likely fail in an higer org with lots of activity records.

try {
    // Attempting to query ALL Task records - very likely > 50,000
    List<Task> allTasks = [SELECT Id FROM Task];
    System.debug('Total tasks found: ' + allTasks.size()); 

} catch (System.LimitException e) {
    System.debug('Caught expected error: ' + e.getMessage()); 
    // You should see the "Too many query rows: 50001" error here.
}


The Fixed Code (Using LIMIT and WHERE)

This version adds both a WHERE clause and a LIMIT to drastically reduce the number of rows retrieved.

// Now run this fixed version. It should succeed.

try {
    // The Fix: Add a selective WHERE clause and a LIMIT
    Date oneMonthAgo = System.today().addMonths(-1);
    List<Task> recentTasks = [SELECT Id, Subject 
                              FROM Task 
                              WHERE CreatedDate >= :oneMonthAgo 
                              AND OwnerId = :UserInfo.getUserId() 
                              LIMIT 1000]; 
                              
    System.debug('Found ' + recentTasks.size() + ' recent tasks for the current user.');

} catch (System.LimitException e) {
    // This block should ideally not be hit now
    System.debug('Unexpected error: ' + e.getMessage()); 
}

 Too many query rows: 50001 Error in Salesforce Apex



If you are preparing for Salesforce interview prepration : Do check our blog

Author

  • Salesforce Hours

    Salesforcehour is a platform built on a simple idea: "The best way to grow is to learn together". We request seasoned professionals from across the globe to share their hard-won expertise, giving you the in-depth tutorials and practical insights needed to accelerate your journey. Our mission is to empower you to solve complex challenges and become an invaluable member of the Ohana.


Discover more from Salesforce Hours

Subscribe to get the latest posts sent to your email.

Leave a Reply

Discover more from Salesforce Hours

Subscribe now to keep reading and get access to the full archive.

Continue reading