1

I'd like to loop over all the results found in a batch job, the issue is that it seems Salesforce can only handle 10,000 at a time.

I think my issue is here:

global Database.QueryLocator start(Database.BatchableContext BC) {
    query = 'SELECT LastName,Email, Phone, Id FROM Lead WHERE IsConverted=False AND Company = null LIMIT 9999';
    return Database.getQueryLocator(query);
}

Is there a simple way improve this so it loops over all my records?

Here is the entire batch job if that helps:

global class batchSyncLeads implements Database.Batchable<sObject> {

    String query;

    global batchSyncLeads() {

    }

    global Database.QueryLocator start(Database.BatchableContext BC) {
        query = 'SELECT LastName,Email, Phone, Id FROM Lead WHERE IsConverted=False AND Company = null LIMIT 9999';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<Lead> leads) {
        SyncLeads sl = New SyncLeads(leads);
    }

    global void finish(Database.BatchableContext BC) {

    }

}
  • I'd like to know how to do this also! – JP Silvashy Dec 11 '15 at 1:43
  • I tend to make my batch query's as generic as possible and then qualify all my data in my execute method, I don't believe it's best practice to make a batch query specific for reusuability purpose.. So if you want to create another batch job for lead you will need to build an entirely new batch class instead of just reusing this one. If its "going slow" does it matter? – EricSSH Dec 11 '15 at 16:46
2

You issue may be that the query is not selective enough? If so simply move some of the processing to the Execute Method as such:

global class batchSyncLeads implements Database.Batchable<sObject> {

    String query;

    global batchSyncLeads() {

    }

    global Database.QueryLocator start(Database.BatchableContext BC) {
        query = 'SELECT LastName,Email, Phone, Id FROM Lead';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<Lead> leads) {
        Lead[] toProcess = New Lead[]{};

        for(Lead l : leads){
          if (l.isConverted == false && Company != null)
              toProcess.add(l);
        }

        SyncLeads sl = New SyncLeads(toProcess);
    }

    global void finish(Database.BatchableContext BC) {

    }

}

By removing the != null filter the query remains selective.

For best performance, SOQL queries must be selective, particularly for queries inside of triggers. To avoid long execution times, the system can terminate nonselective SOQL queries. Developers receive an error message when a non-selective query in a trigger executes against an object that contains more than 100,000 records. To avoid this error, ensure that the query is selective

Working with Very Large SOQL Queries

  • You should be able to leave the isConverted = false in the query so if it works fine with the above, put that back in the query and test it again to ensure it works without issue.

As for the

handle 1000 at a time

Not sure exactly what you mean by that but a batch process by default chunks the records so it will not loop over them all at once no matter what you do. Without specifying the scope:

The default batch size is 200 records

Apex batch Processing

| improve this answer | |
  • Thanks for your answer Eric, I updated my question, it was the 10,000 record limit on Database.queryLocator results OR 10,000 DML statements (I am attempting to merge Leads to Accounts). Is there a way I can invoke the Stateful interface here to be able to say that "the first 9999 records have been looked at, move onto records #10,000-19998, finish when there are no more records left"? – Marv-o Dec 11 '15 at 16:03
  • 1
    The limit on batch apex is 50M records. What I have given above does what you wanted. I am afraid you are going to have to go into a bit more detail as to why you "think" it is 10000. What happened that lead you to believe that? – Eric Dec 11 '15 at 16:09
  • Eric, when I run the batch with the query containing 'LIMIT 9999' my batch maxes out at 9999 records, however when I remove that limit I get an error: 'AsyncApexExecutions Limit exceeded'. I'm assuming I am running into this limit: "Total number of records processed as a result of DML statements, Approval.process, or database.emptyRecycleBin" – Marv-o Dec 11 '15 at 21:25
  • 1
    Use what I have in my answer as the query and just change the scope size when you execute the batch i.e. database.executeBatch(xxxx,10) which would change the batch chunks to 10. If you are still hitting the error then you will need to look at your other code that you are calling from the execute method. Batches can process up to 50M records. But the other limits are still in force for each batch chunk. – Eric Dec 11 '15 at 23:23
  • Excellent, that works a lot better, and I am able to operate upon 100,000 records. However since we have a lot more than that, I tried to crawl through our org 100,000 at a time but incrementing an OFFSET statement in a Batch is not permitted. I can call the database.executebatch(b,200) in the finish method, but am unable to change the records the next iteration runs on. Any suggestions? – Marv-o Dec 15 '15 at 23:31

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.