记一次 API 性能优化

/ 0评 / 0

问题描述

成绩管理页面加载耗时较久,长达 7s 左右,严重影响用户体验

问题分析

首先对函数进行性能分析,通过 time.time() 函数获取当前时间,两次时间的差即为此语句消耗的时间。预计 map_answers() 函数比较耗时,因为该函数会取出所有的结果

第一次测试结果如下

发现第三条语句执行较慢,耗时 7s,查看 mongoengine 官方文档得知,获取结果数目时应该使用 count() 函数,使用 len() 函数会取出所有的结果,放置在本地缓存,所以耗时较长。这也就导致后面的 map_answers() 函数可以直接使用缓存,反而耗时较短。 

修改后进行第二次测试

耗时最长的变成了第四条语句,表明记录迟早都会被全部取出来,此处修改意义不大。 注:all_answers 为 QuerySet,并不是具体数据,for 循环时才会取数据

猜测:mongoengine 将数据转化为 document 实例较慢

mongoengine 可以理解为对pymongo的封装,跟pymongo比,它最大的消耗在从pymongo查询的结果,转换为Document实例,这确实很费资源

mongoengine 在文档实例save的时候,会调用validate来验证每一个field, 这步没有必要,比较耗时

 

https://xwl-note.readthedocs.io/en/latest/software/mongoengine.html

mongoengine 有一个函数 as_pymongo(),使用此函数则不会把数据转化为对象,而是直接以 Python 字典的形式返回。使用 as_pymongo(),然后遍历 answers 进行测试,发现时间变化不大

猜测:SQL查询较慢

使用 explain() 函数进行分析,显示执行时间为 0ms

使用 Navicat 直接进行查询,耗时 7s 左右

产生此差异的原因是,在 mongoDB 中,explain() 函数所显示的执行时间应该是找到符合条件的数据的时间,而 Navicat 查询所显示的时间不仅包括查询的时间,还包括数据 bson 化所需的时间,这个时间性能分析工具没有统计出来。

综上分析,造成函数执行时间较长的根本原因是取出所有记录并转换为 bson 形式的数据耗时较长,怀疑是一条记录中包含的字段过多且比较复杂(包含 Document 嵌套)导致。

解决方案

参考资料

发表评论

邮箱地址不会被公开。 必填项已用*标注