Large Data Processing with Cursors and Queueable Apex Versus Batch Apex

Apex Cursors combined with chained Queueable Apex jobs are a powerful alternative to Batch Apex for processing large volumes of records. Cursors provide the record-traversal capabilities of Batch Apex, but offer greater flexibility in handling parallel jobs. With Batch Apex, only five active Batch Apex jobs are allowed at one time in your org. Jobs beyond this limit are placed in the Flex Queue, which is limited to 100 additional jobs. In orgs with high volumes of background processing, jobs can accumulate in the Flex Queue and delay critical work.

With Apex Cursors, you create a pointer to a large SOQL query result set of up to 50 million rows. The cursor can traverse the result set in chunks across multiple transactions. If you combine a Cursor with a chained Queueable job, each execution processes one or more chunks of records and then re-enqueues itself to handle the next chunk, until all records are processed. This approach has two key advantages over Batch Apex:

  • No parallel batch slot consumption. A chained Queueable job chain counts as a single logical process. It doesn’t consume Batch Apex slots or accumulate in the Flex Queue.
  • Flexibility at scale. Queueable jobs with Cursors can scale the chunk size to adapt to different processing requirements for individual records.

For a sample implementation, see Apex Cursors.

Apex Cursors and Batch Apex query locators (Database.getQueryLocator()) both establish a fixed set of resulting record IDs when they’re created. Subsequent record updates don’t affect the existing set of record IDs. For example, if an object field is updated such that the record no longer meets the initial WHERE clause of the SOQL query, the record ID remains in the result set. Similarly, subsequent changes to record sharing rules don’t alter the result set.

Note

Cursors and Queueables Versus Batch Apex

Detail Batch Apex Cursors+Queueable
Parallel Batch Slot Usage Yes. Counts against the 5-job limit. No
Flex Queue Contention Yes No
Execution Model Ordered and sequential with a fixed scope size Developer-defined order, sequence, and fetch size
Error Isolation Per Batch chunk Transaction Finalizer Per Queueable transaction via a Transaction Finalizer