2

I have a batch job that does lots of calculations and batch size is reduced to 10. Reducing batch size further is not an ideal option at this time due to other factors so to catch Too many DML rows : 10000 error I did this workaround as shown below:

public set<String> objIds;

global void execute(Database.BatchableContext context, List<sObject> scope)
{
    List<String> objIds = new List<String>();
    for (My_Object__c allObjects : (My_Object__c[])scope)
    {
        objIds.Add(allObjects.Id);
    }

    List<Batch_Summary__c> myList = new List<Batch_Summary__c>();

    //code to populate myList goes here
    //
    //

    List<Summary_Log__c> summary = new List<Summary_Log__c>();
    if (myList.size() > 10000)
    {
        for (String id : objIds)
        {
            Summary_Log__c s = new Summary_Log__c();
            s.Name = id;
            summary.add(s);
        }
    }

    if (summary.size() > 0)
    {
        Database.Saveresult[] saveResult = Database.insert(summary, false);
    }
    /*
    else
    {
        Schema.SObjectField upsertField = My_Object__c.Unique_Id__c;
        Database.upsert(myList, upsertField, false);
    }
    */

    //remove out of else block to see if batch throws error
    Schema.SObjectField upsertField = My_Object__c.Unique_Id__c;
    Database.upsert(myList, upsertField, false);
}

For some reason I do get Too many DML rows : 10000 but there is nothing in the logs (Summary_Log__c). Could someone please point out why? Also, is it possible to do something like shown below and have 2 inserts in one go of the batch:

if (myList.size() > 10000)
{
    List<Batch_Summary__c> myList1 = new List<Batch_Summary__c>();
    for(integer j=0; j<10000; j++)
    {
        myList1.add(myList[j]);
    }

    List<Batch_Summary__c> myList2 = new List<Batch_Summary__c>();
    for(integer j=0; j<10000; j++)
    {
        myList2.add(myList[j]);
    }
    Schema.SObjectField upsertField = My_Object__c.Unique_Id__c;
    Database.upsert(myList1, upsertField, false);
    Database.upsert(myList2, upsertField, false);
}
  • 10000 is a transaction limit per execute(); your custom log didn't catch anything because you blew up on a limits exception. A potential workaround is to do the calcs in excel and then use data loader bulk API option = true – cropredy Jun 23 '16 at 18:27
  • To be more clear, it's the transaction limit for the entire execution context. – crmprogdev Jun 23 '16 at 18:29
6

That limit is for the entire transaction. So if you have one DML Operation with 10,000 rows, you cannot perform any other operations in that transaction.

In your first example:

Database.insert(summary, /*allOrNone*/ false);
Database.upsert(myList, upsertField, /*allOrNone*/ false);

If you have 10,000 records in myList and even one single record in the summary list, you will hit a LimitsException.

In your second example, you will have 20,000 rows in the transaction, so it will fail for the same reason.


Note that LimitsException cannot be caught, so you need to do some defensive programming to make sure you head the error off at the pass. You can also find the remaining number of DML Rows using the Limits class.

Integer remainingRows = Limits.getLimitDmlRows() - Limits.getDmlRows();

If this number is greater than the size of myList when you try to upsert it, you're gonna have a bad day.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.