记一次查询超限的优化 单例模式的运用
最近对项目测试时,当导入大量测试数据时,运行程序出现101查询超限??, 只能查看Code 是不是那里不小心在for循环中写了查询语句的低级错误?。 查看了整个代码,没有发现这种情况,只能debug日志,分析日志,由于这其中涉及到 好几个对象的trigger?,最开始的触发是在控制类中,保存一个集合对象。程序涉及到的流程 比较长,打开日志文件长长的输出,只能提高debug的日志等级,首要想到的是看那里日志中的汇总信息, 当某个trigger执行完成后都会有个汇总信息,当执行完后,系统中的Limit已经使用了多少
同时在白板上梳理逻辑,再加上这里保存的对象比较特殊,2种记录类型,
- 在控制类中,总共有2处操作
- 第1处是保存记录类型A的集合
- 第2处是更新记录类型B的集合
- 该对象在before 和 after中不同的记录类型有不同的逻辑处理
- 对象A在更新/插入后,又会涉及到对象B的trigger,会跟据情况生成对象B,如果B存在则更新
- 对象A 查找了 对象B,如果对象B在保存后需要与A关联,A又需要更新自已
再看日志,跟据汇总信息中Number of SOQL 的数量变化,分析Code中查询统计, 最后发现:
- 一个不起眼的根据记录类型的名称查ID 多次执行,因为在每个trigger中处理的操作类中,都需要用记录类型的ID作判断条件
- 我们的trigger上会有个判断,读取系统配置对象中设定的trigger是否执行还是不执行
最后根据这两点已查明的情况作优化,为了不修改原来写好的方法,加上之前看 Advanced Apex Programming for Salesforce.com and Force.com 中提到的静态变量在整个Execution context中是唯一的
“Static variables are maintained throughout an execution context,
and are unique to an execution context”
新建一个类,叫系统配置类,定义一个map集合,提供对外的方法,根据对象名,记录类型名,返回id, 如果集合为空,则去数据库查询放到map中 同理trigger的开关也类似处理,这样一来,查记录类型和trigger就只使用了2次查询次数, 运行程序已没有出现101,Number of SOQL也下降了许多,但也还达到了70多次,跟据执行的逻辑,在对象B保存后,A关联B再更新时,这时不需要A的trigger作任何逻辑处理,通过静态变量的控制跳过trigger, 整个下来,Number of SOQL 只有50✌?。
SFDC的各种限制需要了解情况,在编写代码时,需要注意怎么处理才能最少的消耗限制数 如下表
Description | Synchronous Limit | Asynchronous Limit |
---|---|---|
Total number of SOQL queries issued1(This limit doesn’t apply to custom metadata types. In a single Apex transaction, custom metadata records can have unlimited SOQL queries.) | 100 | 200 |
Total number of records retrieved by SOQL queries | 50,000 | |
Total number of records retrieved by Database.getQueryLocator | 10,000 | |
Total number of SOSL queries issued | 20 | |
Total number of records retrieved by a single SOSL query | 2,000 | |
Total number of DML statements issued2 | 150 | |
Total number of records processed as a result of DML statements, Approval.process, or database.emptyRecycleBin | 10,000 | |
Total stack depth for any Apex invocation that recursively fires triggers due to insert, update, or delete statements3 | 16 | |
Total number of callouts (HTTP requests or Web services calls) in a transaction | 100 | |
Maximum cumulative timeout for all callouts (HTTP requests or Web services calls) in a transaction | 120 seconds | |
Maximum number of methods with the future annotation allowed per Apex invocation | 50 | |
Maximum number of Apex jobs added to the queue with System.enqueueJob | 50 | |
Total number of sendEmail methods allowed | Total number of sendEmail methods allowed | |
Total heap size4 | 6 MB | 12 MB |
Maximum CPU time on the Salesforce servers5 | 10,000 milliseconds | 60,000 milliseconds |
Maximum execution time for each Apex transaction | 10 minutes | |
Maximum number of push notification method calls allowed per Apex transaction | 10 | |
Maximum number of push notifications that can be sent in each push notification method call | 2,000 |
总结
项目中应该创建一个配置类,用来管理配置参数,记录类型可以看作是配置信息的一部分,同时比如一些业务配置数据/系统参数这些记录数不多,可以在执行程序时就加载且加载一次,程序中去读取参数避免多次查询。