2

I've just recently run into a governor limit using Batch Apex with the AggregateResult object and I was hoping someone could clearly explain this limit. I think batch APEX could support up to 50 million records, but when I use AggregateResult, I hit governor limits even though the total records in the object was about 250,000.

How does the AggregateResult limit apply within batch APEX?

Any explanation on how this limit is applied and how to overcome it would be appreciated. Should I simply avoid using AggregateResult within batch APEX? Or, if I do use it, how do I determine when this limit will be hit?

Here is a simple batch program I wrote using AggregateResult. This runs monthly and I'm aggregating Tasks related to a case by user. How can I determine if this will hit limits?

global class MemberCaseAchievementBatch implements Database.Batchable<sObject> {

public string query =  'select Id, Enhancement_Value__c from Case where RecordType.DeveloperName = \'SF_Enhancement\' AND Stage__c = \'Deployed\' AND ClosedDate = THIS_MONTH';
public Set<Id> caseIds = new Set<Id>();
public Set<Id> allCaseIds = new Set<Id>();
Integer totalCompletedCases = 0;
Integer totalAssignedCases = 0;
Double totalCompletedValue = 0;

global database.querylocator start(Database.BatchableContext BC)
{
    return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext BC, Sobject[] scope)
{
    for(Case c : (List<Case>)scope) {
        caseIds.add(c.Id);
        totalCompletedCases++;
        if(c.Enhancement_Value__c == null) {
            totalCompletedValue = c.Enhancement_Value__c;
        }
        else {
            totalCompletedValue += c.Enhancement_Value__c;
        }
    }

    for(Case c : [select Id from Case where RecordType.DeveloperName = 'SF_Enhancement' AND CreatedDate = THIS_MONTH]) {
        allCaseIds.add(c.Id);
        totalAssignedCases++;
    }

    Map<Id, Member_Goal__c> memberGoalsMap = getMemberGoals();
    List<Member_Case_Achievement__c> achievementsToInsert = new List<Member_Case_Achievement__c>();
    AggregateResult[] results = getMemberAchievementMetrics(caseIds);
    Map<String, AggregateResult> tasksAssigned = getMemberTotalTasksAssigned(allCaseIds);
    Date firstDayOfMonth = System.today().toStartOfMonth();
    Date lastDayOfMonth = firstDayOfMonth.addDays(Date.daysInMonth(firstDayOfMonth.year(), firstDayOfMonth.month()) - 1);

    for(AggregateResult ar : results) {
        Member_Case_Achievement__c mca = new Member_Case_Achievement__c();
        if(memberGoalsMap.containsKey(String.valueOf(ar.get('OwnerId')))) mca.Member_Goal__c = memberGoalsMap.get(String.valueOf(ar.get('OwnerId'))).Id;
        AggregateResult aggResult = tasksAssigned.get(String.valueOf(ar.get('OwnerId')));
        mca.Total_Assigned_Tasks__c = (Integer)aggResult.get('expr0');
        mca.Total_Completed_Tasks__c = (Integer)ar.get('expr1');
        mca.Total_Completed_Task_Value__c = (Double)ar.get('expr0');
        mca.Total_Assigned_Cases__c = totalAssignedCases;
        mca.Total_Completed_Cases__c = totalCompletedCases;
        mca.Total_Completed_Value__c = totalCompletedValue;
        mca.Period_Start_Date__c = firstDayOfMonth;
        mca.Period_End_Date__c = lastDayOfMonth;
        achievementsToInsert.add(mca);      
    }
    if(!achievementsToInsert.isEmpty() && achievementsToInsert.size() > 0) {
        insert achievementsToInsert;
    }
}

global void finish(Database.BatchableContext BC) {

}

private AggregateResult[] getMemberAchievementMetrics(Set<Id> caseids) {
    AggregateResult[] groupedResults = [select OwnerId, SUM(Task_Value__c), Count(Id) from Task where WhatId in: caseids AND Subject in ('Requirements','Design','Develop / Config','Unit Testing') group by OwnerId];
    return groupedResults;
}

private Map<String, AggregateResult> getMemberTotalTasksAssigned(Set<Id> caseids) {
    Map<String, AggregateResult> aggregateResultMap = new  Map<String, AggregateResult>();
    for(AggregateResult ar : [select OwnerId, Count(Id) from Task where WhatId in: caseids AND Subject in ('Requirements','Design','Develop / Config','Unit Testing') group by OwnerId]) {
        aggregateResultMap.put(String.valueOf(ar.get('OwnerId')), ar);
    }
    return aggregateResultMap;
}

private Map<Id, Member_Goal__c> getMemberGoals() {
    Map<Id, Member_Goal__c> memberGoalMap = new Map<Id, Member_Goal__c>();
    for(Member_Goal__c mg : [select Id, Member__c from Member_Goal__c where Goal_Period__r.Period_Start_Date__c = THIS_MONTH]) {
        memberGoalMap.put(mg.Member__c, mg);
    }
    return memberGoalMap;
}

}

Is the limit determined by the scope? Or, is it determined by the AggregateResult query?

4

1 回答 1

1

Batch apex 允许您批量运行多达 5000 万条记录。因此,在您的情况下,您可以批量处理超过 5000 万个案例。然而,在每批内部,正常的 Apex 限制仍然适用。

您可以尝试通过Database.executeBatch(yourBatch, scopeSize);where scopeSizeis an Integer between 1 和 2000 来限制每个批次的范围大小。将此设置为较低的数字(默认值为 200)将减少每批次运行的案例,实际上有望减少聚合结果的大小也。

于 2013-11-14T05:10:27.733 回答