近期,数据中心系统负荷大,mysql服务器的CPU动辄达到90%以上。代码和数据表存在很大优化空间。

这里分享一个定时任务批量处理数据的优化过程。

 

先介绍定时任务

先介绍下面2张数据表

  字段 数据量

platform_order

平台交易订单表

 有超过50多个字段。

包括 主键自增id、客户id、客户名称(冗余字段)、服务商id(levy_id)、服务商名称(levy_name,冗余字段)、

付款方式、付款状态、收款人、收款人收款账号(卡号/支付宝/微信)、项目id、付款金额、渠道商、销售代表、

创建时间、最近更新时间、付款完成时间,等等。

550w,每天增量3w

levy_info

服务商基础信息表

字段包括 服务商id(levy_id)、服务商名称(levy_name),等若干字段 50条,很少新增

 

 

项目程序里有一个定时任务,每间隔5分钟,定期为platform_order的冗余字段levy_name赋值。也就是,根据levy表里的信息来更新platform_order表。

 

最初的程序实现

我相信这是绝大多数程序员的实现方式。

 

 

【第一步】求count: select count(1) from platform_order where levy_name is null

【第二步】分页从数据表获取levy_name为null的记录,例如每页1000条,放到List集合里。

【第三步】遍历List集合里的元素,根据记录的levy_id去查levy_info表,得到levy_name,执行SQL:update platform_order set levy_name=#{levy_name} where id=#{id}

 

这个定时任务启动后,不停刷日志,耗时≈3min

改进的程序实现

【第一步】求count:SQL同上

【第二步】如果count>0,则执行一条update语句:update platform_order a join levy_info b on a.levy_id=b.levy_id set a.levy_name=b.levy_name where a.levy_name is null

 

这个实现方式,java着手少了许多代码,不过,数据库倒是出现慢sql了。第二步的update语句耗时10~12s。

count耗时≈2s,整体耗时≈15s

洪荒之力,优化到200ms以内

【第一步】

不再是傻瓜式地一个 levy_name is null 条件了。而是再加一个id>#{maxId}条件。 maxId 值从哪里来?每次定时任务执行完后将最大记录id缓存起来。当然,服务启动后第一次是没有缓存的,就让maxId=0。

再者,执行的sql不是简单的count,而是 select levy_id, min(id) as minId,max(id) as maxId from platform_order where id>#{maxId} and levy_name is null group by levy_id

【第二步】

上面的分组查询得到一个List集合,遍历集合元素,同样根据levy_id查levy_info表得到levy_info记录。

然后,如果你跟得上我的节奏,你应该能猜到,执行这样一个SQL:


update platform_order set levy_name=#{levy_name} where levy_id=#{levy_id} and id between #{minId} and #{maxId} and levy_name is null

View Code

要提到的一点是,根据levy_id获取levy_info记录,我使用了缓存,缓存24h,是不是很豪横~

【第三步】 

缓存最大id  —> maxId

 

这么优化之后,job的耗时在100ms~200ms之间,这个耗时足可以令伙伴们尖叫!

 

 

原文地址:http://www.cnblogs.com/buguge/p/16812025.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性