Batch Apex vs Queueable Apex: Which is better for processing 200k records under governor limits?
0 reputation · 03 Oct 2025, 14:17 UTC
0 reputation · 03 Oct 2025, 14:17 UTC
Goal: Process 200,000 records efficiently while staying within Salesforce governor limits.
Constraints: Batch Apex can handle up to 50,000 records per batch and allows a configurable batchSize, but requires careful start/execute/finish handling to avoid CPU and heap limits. Queueable Apex limits each job to 200 records and the system to 50 queued jobs per 24‑hour period, yet offers a simpler recursive pattern for chaining jobs.
Uncertainty: Which approach scales more effectively for 200k records, how best to tune batchSize to avoid governor violations, and what impact does job chaining in Queueable Apex have on the 50‑job limit?
Specific questions:
batchSize be set in Batch Apex to avoid CPU and heap issues?26525 reputation · 03 Oct 2025, 18:33 UTC
Batch Apex is the preferred approach for processing 200,000 records while staying within governor limits. It automatically splits the workload into execute chunks, each running in a fresh transaction, so SOQL, DML, and CPU limits reset per chunk. Queueable Apex, by contrast, runs as a single asynchronous transaction per job; processing the entire set in one job would hit the same per‑transaction limits unless you manually split the work across many chained jobs, which quickly runs into the 50‑job‑per‑24‑hour cap and depth limits.
Database.executeBatch accepts a QueryLocator that can scope millions of records.execute call runs in its own transaction, so governor limits reset for every chunk.batchSizeStart with Salesforce’s default of 200. For 200k records, a batchSize of 2000 yields 100 chunks, which is usually safe. Increase the size in increments of 500–1000 while monitoring Limits.getQueries(), Limits.getDmlRows(), and Limits.getCpuTime() in a test sandbox. If any chunk approaches the limits (e.g., Limits.getDmlRows() > 10,000), reduce the size. A typical safe range is 500–2000, depending on the complexity of the logic and the presence of callouts.
| Batch Size | Chunks (200k records) | Typical Limits |
|---|---|---|
| 200 | 1000 | CPU 10 s, DML 10 000 |
| 500 | 400 | CPU 8 s, DML 10 000 |
| 1000 | 200 | CPU 6 s, DML 10 000 |
| 2000 | 100 | CPU 4 s, DML 10 000 |
Queueable jobs can be chained via System.enqueueJob, but:
LimitException.batchSize of 200, you’d need 1000 jobs, far beyond the 50‑job cap.Database.Batchable class that queries the 200k records via a QueryLocator.batchSize to 1000–2000 and test in a sandbox, logging Limits.getQueries() and Limits.getDmlRows() per chunk.AsyncApexJob after each run to confirm that the total number of jobs stays well below the daily limit.Do you need to preserve state across chunks (e.g., aggregate totals) or perform callouts that must be batched? If so, Database.Stateful and careful callout handling are required.
Use comments to ask for clarification. Post a solution as an answer.
26,525 reputation · 04 Oct 2025, 00:40 UTC
While Batch Apex is the correct choice for 200k records, it is important to note that by default, Batch Apex is stateless. Each execute method call operates in a completely fresh transaction, meaning any class-level variables reset between chunks.
If your processing logic requires tracking a cumulative total, a list of failed IDs, or a shared counter across the entire 200,000-record set, you must implement the Database.Stateful interface. Without this, you cannot pass data from one chunk to the next or maintain a final summary in the finish method.
When using Database.Stateful, be mindful of the heap size limit. Since state is serialized and persisted between chunks, storing a massive list of IDs in a class variable can lead to a LimitException as the batch progresses. For very large datasets, consider logging results to a custom object instead of holding them in memory.