写点什么

思路一转,春暖花开!动动手指,这段程序性能又双叒提升 2s~15s

  • 2022-12-03
    北京
  • 本文字数:1429 字

    阅读完需:约 5 分钟

思路一转,春暖花开!动动手指,这段程序性能又双叒提升2s~15s

性能优化说明:判断数据表里是否有数据,用 limit 1/top 1 取代求 count,这一点对于大表来说相当明显。思路一转,春暖花开!


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


这里分享一个定时同步数据的 Job 任务的优化过程。

先上代码

public void executeJob(String jobParameter) {
//获取风控个体工商业者信息表数据总计,如果没有任何数据,则需要初始化 int sohoCount = sbhSohoManager.count(); if (sohoCount == 0) { // 首次同步数据 ... } else { // 非首次,增量同步数据 ... }}
复制代码


从这段代码不难看出来,根据表的数据量来走不同的分支处理逻辑。


其中,sbhSohoManager#count 是 mybatisplus 原生的 count 方法。对应 SQL 是:SELECT COUNT(1) FROM sbh_soho 


查 log,发现这么一个 count,耗时竟然 2s~15s。


从数据库知识看解释,也不难理解,因为这个宽表的数据量已经快上千万条记录了(24 个字段,9,059,527 条记录),求 count 自然就会慢下来。只不过,是我们没有及时意识到这个数据量级,因此也就没有采取优化。


优化方案

要实现这样一个判断,不用求 count,取一条记录的耗时就小到数个 ms 了。对应的 SQL 是: SELECT * FROM sbh_soho limit 1



因此改一下逻辑。


public void executeJob(String jobParameter) {
//获取风控个体工商业者信息表数据总计,如果没有任何数据,则需要初始化 int sohoCount = sbhSohoManager.hasRecord(); if (sohoCount == 0) { // 首次同步数据 ... } else { // 非首次,增量同步数据 ... }}
复制代码


其中,sbhSohoManager#hasRecord 巧用 mybatisplus 的 QueryWrapper#last("limit 1")实现 SQL 里的 limit,定义如下


    /**     * 仅判断表里有没有数据     * @return     */    public boolean hasRecord(){        QueryWrapper<SbhSoho> objectQueryWrapper = new QueryWrapper<>();        objectQueryWrapper.last("limit 1");        SbhSoho sbhSoho =getOne(objectQueryWrapper); //baseMapper.selectOne( null);        return sbhSoho!=null;    }
复制代码

还有优化空间

这是一个同步数据的 job。定期从源库同步一个表的增量数据到当前库。


基于此,作为高端程序员的你,也许会想到, 判断当前数据表里是否存在数据其实不用每次查库。


所以,内存/缓存又派上用场了。————————————>另起一段。


当前 JobService 里定义一个 static boolean 的 field: isFirstTime,默认值为 false。 job 首次跑的时候.... ——还是写代码吧,描述起来太费脑子费文字费眼球还不易懂。


@Servicepublic class SbhSohoSyncBizJobImpl {    private static boolean isFirstTime = true;        public void executeJob(String jobParameter) {
if ( isFirstTime == true) { isFirstTime = ! CacheUtil.getCache("onlyoncekey" + getClass().getSimpleName(), TimeUnit.DAYS.toSeconds(30), () -> sbhSohoManager.hasRecord()); }
//获取风控个体工商业者信息表数据总计,如果没有任何数据,则需要初始化 if (isFirstTime == true) { // 首次同步数据 ... } else { // 非首次,增量同步数据 ... } }}
复制代码


CacheUtil.getCache 是利用 Redist#get、Redis#set、Supplier<T>封装一个缓存 util 方法。



发布于: 刚刚阅读数: 6
用户头像

还未添加个人签名 2020-08-17 加入

还未添加个人简介

评论

发布
暂无评论
思路一转,春暖花开!动动手指,这段程序性能又双叒提升2s~15s_MySQL_GREENSOUL_InfoQ写作社区