目录
1、背景
系统上线后,被用户反应系统很多功能响应时长很慢。用户页面影响速度有要求,下面针对查询数据表速度慢、调别人接口速度慢、导入速度慢、导出速度慢、统计功能速度慢的优化进行介绍
2、优化实现
2.1查询数据表速度慢
有个业务,当时开发的时候,预估数据量是20W左右,结果上线之后,因为用户多次DDL操作数据库对数据全量进行逻辑删除以及数据有版本信息,导致数据达到百万级别。 每次查询的时候不带条件耗时至少5秒。
针对以上情况进行的措施如下:
1、后端创建一个定人清理垃圾数据的任务,每天晚上对用户DDL操作数据表进行逻辑删除的数据,进行物理删除。这可以控制数据表数据量,数据量可控制到50w以内,不会无限膨胀。
2、给这张大表加索引,经常使用的查询条件加索引
3、因为涉及到多版本数据。对数据表进行分别,最新版本数据存一张表,所有版本数据存历史表。列表查询查最新版本数据就行,这个数据量控制在10w
4、针对这张表的操作,不管是查询还是删除都批量进行
做了以上优化,查询时长控制到2秒内
2.2调别人接口速度慢
目录树,是懒加载,查一次要调2次外部接口,第一次查1级目录,第二次查2级目录。调一次接口耗时2秒,2次耗时4秒,加上数据统计3秒,加载目录树耗时7秒。
针对这种情况优化如下:
1、后端做个定时任务,每30分钟主动调第三方接口查一级目录、二级目录数据,放入redis缓存,页面查询几乎都是命中缓存。2次接口控制到1.5秒
2、统计数量的sql,加缓存,缓存30分钟。如果有数据新增,删除等操作主动删除更新缓存。
做了以上2步,加载控制在3秒内
2.3导入速度慢
用户一次导入10w条数据,分22个sheet页,每次导入要花2个小时
针对这种情况优化如下:
1、多线程读取sheet页的数据,对数据进行批量校验
2、凡是涉及到操作数据表读写的地方,尽可能的改成批量读写
3、如果校验中用到的一些调第三方接口的有用信息,在校验阶段就把这些信息保存,不重复调第三方接口
做了以上3步,导入控制在30分钟内
2.4导出速度慢的做出介绍
用户一次导出10w条数据,居然花了半小时
针对这种情况优化如下:
1、查询数据库的时候,批量一次查10w,而不是循环查询10w次
2、10w条数据,有一个是要拿目录id,查询目录名称,居然循环了10w次。把第一步数据目录id进行去重,批量调第三方接口查目录信息
做了以上2步,导入控制在1分钟内
2.5统计功能速度慢
系统首页,有各种图标的统计功能。有些统计数据有查几张大表数据,接口时长可达10几秒
针对这种情况优化如下:
1、创建定时任务,每天晚上跑出统计数据到统计表。实现数据T-1的展示。如果时效性要求高,也可半小时或者10分钟统计一次
按以上方案,接口都控制在2秒内
3、总结
加速性能一般考虑:
1、缓存预热。 定时任务,每半小时刷缓存,接口只查缓存数据
2、数据表加索引
3、定时清理垃圾数据
4、定时任务预先生成数据,牺牲实时性
5、引入多线程
6、操作数据库表要尽快批量处理,特别是大数据的导入导出
7、打印耗时日志
StopWatch sw = new StopWatch(); sw.start("importGzTemplate开始导入规则模板"); sw.stop(); sw.start("importGzTemplate校验1"); sw.stop(); sw.start("importGzTemplate写入数据表"); sw.stop(); log.info(sw.prettyPrint());