Apex代码优化:拆分嵌套for循环规避Governor Limits
Apex嵌套循环优化方案:拆分循环并保持逻辑一致
原代码的嵌套循环时间复杂度为O(N*M)(N为CIP记录数,M为CPO记录数),大数据量下易触发Salesforce Governor Limits。以下是拆分循环的优化方案,完全保留原逻辑且效率更高:
优化后代码
//Create some CIP__c records List<cip__c> cipRecords = new List<cip__c>(); cipRecords.add(new cip__c(StartDate__c = Date.newInstance(2023, 1, 1), EndDate__c = Date.newInstance(2023, 12, 31), SellingRole__c = 'Salesperson', PEKMapping__c = 'PEK1')); cipRecords.add(new cip__c(StartDate__c = Date.newInstance(2023, 1, 1), EndDate__c = Date.newInstance(2023, 6, 30), SellingRole__c = 'MuleSfotAE', PEKMapping__c = 'PEK2')); Set<String> Roles=new Set<String>(); Roles.add('Salesperson'); Roles.add('MuleSoftAE'); Roles.add('Sales Cloud'); Roles.add('Service Cloud'); //Create a set of unique commission periods Set<Date> uniqueDates = new Set<Date>(); uniqueDates.add(Date.newInstance(2023, 1, 31)); uniqueDates.add(Date.newInstance(2023, 2, 28)); uniqueDates.add(Date.newInstance(2023, 3, 31)); uniqueDates.add(Date.newInstance(2023, 4, 30)); uniqueDates.add(Date.newInstance(2023, 5, 31)); uniqueDates.add(Date.newInstance(2023, 6, 30)); uniqueDates.add(Date.newInstance(2023, 7, 31)); uniqueDates.add(Date.newInstance(2023, 8, 31)); uniqueDates.add(Date.newInstance(2023, 9, 30)); uniqueDates.add(Date.newInstance(2023, 10, 31)); uniqueDates.add(Date.newInstance(2023, 11, 30)); uniqueDates.add(Date.newInstance(2023, 12, 31)); //Create a map of CPO Id to commission period Map<Id, Date> cpowithDates = new Map<Id, Date>(); cpowithDates.put('001A00000123abc', Date.newInstance(2023, 1, 31)); cpowithDates.put('001A00000123def', Date.newInstance(2023, 2, 28)); cpowithDates.put('001A00000123ghi', Date.newInstance(2023, 3, 31)); cpowithDates.put('001A00000123jkl', Date.newInstance(2023, 4, 30)); cpowithDates.put('001A00000123mno', Date.newInstance(2023, 5, 31)); cpowithDates.put('001A00000123pqr', Date.newInstance(2023, 6, 30)); // --- 优化逻辑开始 --- // 1. 提前过滤符合角色要求的CIP记录,减少后续处理量 List<cip__c> validCipRecords = new List<cip__c>(); for (cip__c cip : cipRecords) { if (Roles.contains(cip.SellingRole__c)) { validCipRecords.add(cip); } } // 2. 构建日期到CPO ID列表的映射,避免重复查询 Map<Date, List<Id>> dateToCpoIdsMap = new Map<Date, List<Id>>(); for (Id cpoId : cpowithDates.keySet()) { Date commPeriod = cpowithDates.get(cpoId); if (!dateToCpoIdsMap.containsKey(commPeriod)) { dateToCpoIdsMap.put(commPeriod, new List<Id>()); } dateToCpoIdsMap.get(commPeriod).add(cpoId); } // 3. 生成最终映射,无嵌套循环 Map<Id, String> cpoidToPekMap = new Map<Id, String>(); for (cip__c validCip : validCipRecords) { for (Date commDate : dateToCpoIdsMap.keySet()) { if (validCip.StartDate__c <= commDate && validCip.EndDate__c >= commDate) { // 批量处理该日期下的所有CPO ID for (Id cpoId : dateToCpoIdsMap.get(commDate)) { cpoidToPekMap.put(cpoId, validCip.PEKMapping__c); } } } } // --- 优化逻辑结束 ---
核心优化点
- 提前过滤无效数据:先排除不符合角色要求的CIP记录,减少后续循环的处理对象
- 反转映射关系:将CPO ID→日期的映射转为日期→CPO ID列表,避免重复查询日期对应的ID
- 拆分嵌套循环:将原O(N*M)的嵌套循环拆分为三次线性遍历,整体时间复杂度更优,降低Governor Limits触发风险
- 逻辑一致性:保留原代码中"后匹配的CIP会覆盖前序匹配结果"的逻辑,输出结果与原代码完全一致
额外优化(针对大量日期场景)
如果佣金日期数量较多,可将日期集合转为有序列表,通过区间查找减少遍历次数:
// 将日期集合转为有序列表 List<Date> sortedDates = new List<Date>(uniqueDates); sortedDates.sort(); // 替换第三步的日期遍历逻辑 for (cip__c validCip : validCipRecords) { Date start = validCip.StartDate__c; Date end = validCip.EndDate__c; // 找到区间起始索引 Integer startIdx = 0; while (startIdx < sortedDates.size() && sortedDates[startIdx] < start) { startIdx++; } // 找到区间结束索引 Integer endIdx = sortedDates.size() - 1; while (endIdx >= 0 && sortedDates[endIdx] > end) { endIdx--; } // 只遍历区间内的日期 if (startIdx <= endIdx) { for (Integer i = startIdx; i <= endIdx; i++) { Date commDate = sortedDates[i]; for (Id cpoId : dateToCpoIdsMap.get(commDate)) { cpoidToPekMap.put(cpoId, validCip.PEKMapping__c); } } } }
内容的提问来源于stack exchange,提问作者Sri
相关产品推荐
相关产品推荐

