MySql优化浅析

 

优化点:合理的使用索引,可以大幅度提升sql查询效率,特别查询的表的数据量大的时候,效果明显。一.引言

  公司的产品XX出行上线正式运营,随着数据量的变大,司机2000+,日订单1万+,注册乘客26W+,MySql的一些语句查询效率低下,严重的达到10秒级别以上,严重的影响系统服务。故公司安排我负责数据库方面的工作。(吐槽,公司不是很大,但是DBA都没,java是全能的,啥都要搞一搞)

二.分析

  从网上寻找到的资源,可以分成1)业务层面逻辑优化;2)业务层面数据结构优化;3)Sql语句优化。下面实例均来自该项目实际运营中出现的。

  1)业务层面逻辑优化

  案例:司机发送消息接口,接口实现逻辑:后台创建一条司机信息-》推送给司机端-》司机端主动拉取获取消息接口-》内部实现(需优化)-》返回接口信息给司机端。内部实现代码如下:

/* 
 遍历表yy_common_driver_message,根据条件取的全部的msgId(1) 
 遍历表yy_common_message_status,根据条件取得已发送的msgId;(2) 
 将未发送的msg(1-2),新增到表yy_common_message_status 
 */  
 Map<String,Object> map = new HashMap<String,Object>();  
 map.put("targetUuid", params.get("targetUuid"));  
 List<String> existsList = getMsgUuids(map);  
 AjaxList ajaxList = commonDriverMessageService.getUuids(params);  
 if(ajaxList.isSuccess()){  
     List<String> allList = (List<String>) ajaxList.getData();  
     List<CommonMessageStatusDto> list = new ArrayList<CommonMessageStatusDto>();  
     for(String uuid : allList){  
         if(!existsList.contains(uuid)){  
             //如果id不包含在已发送,表yy_common_message_status插入新数据  
             CommonMessageStatusDto dto = new CommonMessageStatusDto();  
             dto.setUuid(StringUtil.buildUUID());  
             dto.setMessageUuid(uuid);//msgId  
             dto.setTargetUuid(params.get("targetUuid").toString());  
             dto.setStatus(CommonMessageStatusDto.STATUS_UNREAD);//未读  
             dto.setType(CommonMessageStatusDto.TYPE_SYSTEM);//系统消息  
             dto.setBusinessType(new Integer(params.get("businessType").toString()));  
             dto.setTargetType(CommonMessageStatusDto.TARGET_TYPE_DRIVER);//司机  
             dto.setAppid(params.get("appid").toString());  
             list.add(dto);  
         }  
     }  
     if(list.size()>0){//如果有。则新增  
         commonMessageStatusMapper.addBatch(list);  
     }  
 }  

  初心的设计是为了司机端调用接口的时候,才生产中间表yy_common_message_status的数据,但是由于需求变更,需要主动批量推送给司机,变相是主动触发司机调用接口。这时候,这个设计就不合适了。客户在使用的时候,用车高峰期的时候,主动发送司机消息给所有的司机,司机端收到推送的时候,会主动调用该接口,导致系统查询缓慢。根据讨论结果,内部实现修改为在新增司机消息的时候,新建一个线程,批量插入中间表记录,司机端调用接口的时候,只需要直接执行中间表-消息表的sql语句。优化点:减少数据库交互次数。

  2)业务层面数据结构优化

  软件使用的乘客数不断上升,26W+,一些查询乘客表的sql语句,查询缓慢。Sql语句:SELECT * from yy_passenger where mobile = '15822230119',耗费时间0.66s,查看Mysql执行计划:

根据查询条件,创建索引,使用索引后,执行SQL查询,耗时0.047s,查看执行计划:

优化点:合理的使用索引,可以大幅度提升sql查询效率,特别查询的表的数据量大的时候,效果明显。

 

   3)Sql语句优化

  可以参考链接:http://blog.csdn.net/jie_liang/article/details/77340905,写sql的时候需要注意的,目前就举一例子,营运上遇到的。如下一段mybatis代码

<select id="getTodayDriverMonitorList" resultType="driverMonitorListBean">  
        select d1.uuid driverUuid,  
                d1.type,  
                d1.mobile,  
                d1.name,  
                d1.plate_num plateNum,  
                d1.isWork,  
                d1.minTime,  
                d1.maxTime,  
                d1.timeSum,  
                count(o.uuid) orderCount,  
                sum(f.order_fare) fareSum,  
                sum(f.trip_distance) distanceSum  
        from (  
        select d.uuid,d.type,d.mobile,d.name,d.is_work isWork,c.plate_num,min(l.onWork_time) minTime,max(l.onWork_time) maxTime,sum((TIME_TO_SEC(IFNULL(offWork_time,now())) - TIME_TO_SEC(onWork_time))) timeSum  
        from yy_driver d  
        inner join yy_driver_sign_log l on d.uuid = l.driver_uuid and l.workday = date_format(now(),'%Y-%m-%d')  
        inner join yy_car c on c.uuid = d.car_uuid  
        where 1=1  
        <if test="business != 99 and business !=null">AND d.type = #{business}</if>  
        group by d.uuid,d.mobile,d.name,c.plate_num,d.type,d.is_work  
        ) d1  
<strong>        left join (SELECT uuid,actual_driver_uuid FROM yy_order where create_time >= curdate() and create_time lt; date_add(curdate(), interval 1 day))o ON o.actual_driver_uuid = d1.uuid  
</strong>        left join yy_order_fare f on o.uuid = f.order_uuid  
        group by d1.uuid,d1.type,d1.mobile,d1.name,d1.plate_num,d1.minTime,d1.maxTime,d1.timeSum  
    </select>  

  

修改后,执行时间0.52s。

优化点:SQL语句根据实际情况进行优化。

三.结尾

  经过这次的SQL管理工作,对SQL优化有一个比较浅的涉及,个人的认为业务逻辑的实现和表结构的设计是顶层设计,而sql语句的优化是在此的基础上。常用的优化方法:索引的创建和分表方式(未涉及,只听说),而索引的创建在合理性,数据库中以空间换时间来实现,SQL语句的查询要避免一些语法导致无法引用索引,而且要根据实际的情况使用好子查询,避免使用全字段查询。

 

posted @ 2018-05-12 10:59  knbsyoo  阅读(137)  评论(0编辑  收藏  举报