FATAL_ERROR|System.LimitException:SOQL 查询太多:201

FATAL_ERROR|System.LimitException: Too many SOQL queries: 201

我在 apex 中收到太多 SOQL 查询 201 错误 class

我试图检查循环内的查询数量 以下是准确的错误 -

11:48:43.9 (2785518121)|FATAL_ERROR|System.LimitException: Too many SOQL queries: 201

Class.GEN_CalculateActToWinScores.calcUserEligible: line 1343, column 1
Class.GEN_ActonFactsScoreUserEligibleBatch.execute: line 74, column 1

11:48:43.9 (2851114444)|CODE_UNIT_FINISHED|GEN_ActonFactsScoreUserEligibleBatch 11:48:43.9 (2852614277)|EXECUTION_FINISHED

下面是方法 GEN_CalculateActToWinScores.calcUserEligible -

的代码
   // Method for set user as ready for AoF
   public static void calcUserEligible(List<User> usersList ){

            List<Act_on_Facts__c> actOnFactDelete = new List<Act_on_Facts__c>();
            Set<String> oppOpenStageNameSet = new Set<String>();
            oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_IDENTIFY);
            oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_QUALIFY);
            oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_PROPOSE);
            oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_NEGOTIATE);

            Set<String> oppReadOnlyRecordTypeNameSet = new Set<String>();
            oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_SINGLE_ACCOUNT_OPP_RECORDTYPENAME);
            oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_WON_AND_DONE_OPP_RECORDTYPENAME);
            oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_CHILD_OPP_RECORDTYPENAME);
            oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_MULTI_ACCOUNT_OPP_RECORDTYPENAME);  

            if(usersList.size() > 0){

                List<Id> idList = new List<Id>();
                Integer countResult = 0;            
                List<User> newUserList = new List<User>();                

                Integer limitQuery;     //10000 //2001
                Integer limitResult;    //2000

                if(CSL_ActOnFactsLimits__c.getValues('QUERY_LIMIT') != null){
                    limitQuery = Integer.valueOf(CSL_ActOnFactsLimits__c.getValues('QUERY_LIMIT').Value__c);
                }
                if(CSL_ActOnFactsLimits__c.getValues('MAX_QUERY_RESULTS') != null){
                    limitResult = Integer.valueOf(CSL_ActOnFactsLimits__c.getValues('MAX_QUERY_RESULTS').Value__c);  
                }   


                Boolean eligible = true;

                for (User userElement : usersList){

                    String logDetail = ' QUERY_LIMIT:limitQuery: '+limitQuery+' MAX_QUERY_RESULTS:limitResult: '+limitResult;

                    logDetail += ' userElement.id: '+userElement.id;

                    eligible = true;

                    CSH_ActOnFacts_UserEligible__c userEligible = null;
                    if(CSH_ActOnFacts_UserEligible__c.getValues(userElement.id) != null){
                        userEligible = CSH_ActOnFacts_UserEligible__c.getValues(userElement.id);
                    }

                    CSH_ActOnFacts_UserEligible__c profileEligible = null;
                    if(CSH_ActOnFacts_UserEligible__c.getValues(userElement.ProfileId) != null){
                         profileEligible = CSH_ActOnFacts_UserEligible__c.getValues(userElement.ProfileId);
                    }

                    List<Act_on_Facts__c> actonfacts = [select id from Act_on_Facts__c where Lookup_User__c = : userElement.id limit 1];

                    if(userElement.ManagerId == null){
                        userElement.Line_Manager_Optional__c = true;
                        userElement.Act_On_Facts_Manager_List__c = null;
                    }

                    if(userElement.Default_Macro_Segment__c == null){
                        userElement.Default_Macro_Segment__c = 'None';
                    }

                    if (userElement.IsActive == false){
                        eligible = false;
                    }else if(profileEligible != null || userEligible != null) {   
                         eligible = false;                      
                    }else{

                        countResult = [select count() from Account WHERE OwnerId = :userElement.id LIMIT :limitQuery];
                        logDetail += ' Account.countResult: '+countResult;

                        if(countResult!=null && countResult > limitResult ){
                            eligible = false;
                        }

                        if(eligible){   

                          if(oppOpenStageNameSet !=null && oppOpenStageNameSet.size()>0 && oppReadOnlyRecordTypeNameSet !=null && oppReadOnlyRecordTypeNameSet.size()>0){             

                            countResult = [select count() from Opportunity WHERE OwnerId = :userElement.id AND StageName IN:oppOpenStageNameSet AND RecordType.DeveloperName NOT IN: oppReadOnlyRecordTypeNameSet LIMIT :limitQuery];
                            logDetail += ' Opportunity.countResult: '+countResult;

                            if(countResult!=null && countResult > limitResult ){
                              eligible = false;
                            }
                          }                              
                        }                   
                    }

                    if(!eligible){

                        userElement.Act_on_Facts_Eligible__c = false;

                        // remove user from Act on Facts
                        if(actonfacts != null && actonfacts.size()>0){
                            for(Act_on_Facts__c a : actonfacts){
                                actOnFactDelete.add(a);
                            }
                        }

                    }else{
                        userElement.Act_on_Facts_Eligible__c = true;
                    }      

                    logDetail += ' userElement.Act_on_Facts_Eligible__c: '+userElement.Act_on_Facts_Eligible__c;

                    ApplicationLog.logEntry(ApplicationLog.SEVERITY_INFO, 'A2WBatch', 'GEN_ActonFactsScoreUserEligibleBatch:'+userElement.id+': ', logDetail);

                    newUserList.add(userElement);
                }

                try{
                    if(newUserList.size()>0){
                        update newUserList;   
                        system.debug('HC Update- newUserList ' + newUserList);                      
                    }

                    if(actOnFactDelete.size()>0){
                        delete actOnFactDelete;
                        system.debug('HC Update- actOnFactDelete ' + actOnFactDelete);
                    }
                }catch (Exception e){
                    system.debug('Error updating user ' + e);
                }  
            }
   } 

代码 GEN_ActonFactsScoreUserEligibleBatch.execute-

    global void execute(Database.BatchableContext BC, List<sObject> scope){
         CSH_A2W_Settings__c a2wCS = CSH_A2W_Settings__c.getInstance();         
        if(scope != null){ 

            List<User> userList = scope;

            if(userList.size()>0){

                if(CSL_ActOnFactsLimits__c.getValues('run_userTrigger') != null){
                    CSL_ActOnFactsLimits__c run_userTrigger = CSL_ActOnFactsLimits__c.getValues('run_userTrigger');
                    run_userTrigger.Value__c = 'false';
                    update run_userTrigger; 
                }

                //GEN_CalculateActOnFactsScores.calcUserEligible(userList);     //Commented as part of Decommission activity of AoF
                if(a2wCS != null && a2wCS.Enabled_in_Batches__c == True){
                    GEN_CalculateActToWinScores.calcUserEligible(userList);
                }
            } 
        } 
    }

我正在尝试分析什么是消除这些错误的最佳方法,或者是否有任何替代方法来实现这些错误。

所有这些都是循环中的查询:

for (User userElement : usersList){
    ...
    List<Act_on_Facts__c> actonfacts = [select id from Act_on_Facts__c where Lookup_User__c = : userElement.id limit 1];
    ...
    countResult = [select count() from Account WHERE OwnerId = :userElement.id LIMIT :limitQuery];
    ...
    [select count() from Opportunity WHERE OwnerId = :userElement.id AND StageName IN:oppOpenStageNameSet AND RecordType.DeveloperName NOT IN: oppReadOnlyRecordTypeNameSet LIMIT :limitQuery];

作为一种非常快速且肮脏的解决方案,您可以更改批处理的大小(每次执行传递多少条记录)。默认值为 200。

使用可选参数 Database.executeBatch(new GEN_ActonFactsScoreUserEligibleBatch(), 10); 调用您的 class,看看是否有帮助。

"Proper" 修复需要进行一些重组,将查询排除在循环之外,可能使用一些以用户 ID 为关键的地图...

如果这些是自定义对象,"pro" Apex 开发人员会作弊,一次性进行这些查询,提取用户和相关列表,例如

SELECT Id,
    (SELECT Id FROM Accounts__r LIMIT 1),
    (SELECT Id FROM Opportunities__r WHERE ... LIMIT 1),
    (SELECT Id FROM Act_On_Facts__r)
FROM User
WHERE Id IN :scope

这在这里不起作用,因为从帐户到所有者的关系没有一个好听的名字("Accounts" 不起作用)。您应该仍然可以在自定义对象上执行此操作(我示例中的最后一个子查询,您可以在循环外调用它)

您可能仍然可以完成类似的操作,但可能需要查看与共享相关的表格...我认为可行,但如果您有时间尝试一下。如果你不这样做 - 改变范围大小并称之为一天。会执行更长的时间,但 1-liner 修复在我看来是一个胜利。