0

What do I have?

  1. Two objects ObjectA and ObjectB without any trigger/process builder/flow.
  2. I create a trigger on ObjectA to create the same number of records on ObjectB

What is my test case?

  1. Insert 9500 records in ObjectA and test if 9500 records are getting created in ObjectB.

What went wrong?

  1. When I ran the logic to create 9000 records in the anonymous window, I get an error 'Too many DML rows: 10001'. Of course!

  2. I moved my logic into a queueable class to ensure the DML of object B is not adding to the existing DML rows count and starts getting CPU TIME LIMIT ERROR.

My analysis:

  1. Even if I disable the trigger and run it for 6000 rows, the time is taken (debug: cpuTime) is approximately 11 seconds.
  2. With the trigger on, it comes as 13 seconds.

I want to know what I could do to ensure that at least 10k records in objectA can be processed without having the CPU timeout limit touched?

2 Answers 2

6

You can't test at that data volume.

The DML rows limit is 10,000 in a transaction. You're seeking to run a test that inserts a total of 18,000 records in a transaction (both an Anonymous Apex execution and, loosely, a unit test area bounded by a transaction). That's never going to be possible.

The 200 record batch you see in your logs is simply the trigger batch that first exceeds the 10,000 row limit across your transaction.

You won't be able to test with more than 5,000 records in a single transaction.


What should be the workaround? There could be cases wherein I would be creating as many records in object B as 10 times of object A after processing.

You need to move record creation out of the trigger and into an asynchronous process. In this case, you'd likely be using Batch Apex or a Queueable Apex chain.

2
  • Thank you for this explaination. 1. When I put the limit as 5000 for insert in ObjectA, I get 'Apex CPU time limit exceeded'. 2. What should be done if I have a list of 30K which gets formed after processing trigger context and is to be inserted? Jun 19, 2021 at 19:42
  • 2
    @RajeevGodara You must architect your application to work with the governor limits of the Salesforce platform. You can't just insert as much data as you want in one go; you will hit a variety of limits, including DML rows, possible SOQL queries, CPU time, etc. You should familiarize yourself with the use of asynchronous Apex and batch processing if you need to work with tens of thousands of records. Trailhead can get you started.
    – David Reed
    Jun 19, 2021 at 21:52
3

It is generally acceptable for bulk unit tests to use 200 records at a time. That is because this is the largest amount of data that will occur in a trigger from the UI or API (Apex, of course, is an exception, but you should only test for more than 200 if you reasonably expect it to occur). Even then, you may find that you'll run into CPU or heap limits. If so, you need to reduce the size until you can consistently pass without hitting either limit. For example, I've seen orgs that had so much Contact trigger logic that anything larger than 10 records started risking CPU timeout errors (10 contacts ran in about 9.9 seconds on average).

If you need more than 200 rows, it's strongly suggested you use asynchronous code to have up to 60 seconds of CPU and twice as much heap. If you expect you need much more than that, it's time to go to a Batchable or Queueable solution specifically. Or, you can "test" your code using the Apex Data Loader, for example, to load 9,000 rows via the API. This will break up the transactions into batches of 200, though, so you'll end up with the same result as running an Execute Anonymous script 180 times.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .