首先是表结构,部分字段脱敏已删除
CREATE TABLE `log_device_heart` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `device_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `time_periods_begin` datetime NOT NULL, `time_periods_end` datetime DEFAULT NULL, `create_time` timestamp NULL DEFAULT NULL, `date` datetime DEFAULT NULL, `num` int DEFAULT NULL, `other_num` int DEFAULT '0', PRIMARY KEY (`id`) USING BTREE, KEY `device_number` (`device_number`) USING BTREE, KEY `time_periods_begin_desc` (`time_periods_begin` DESC) ) ENGINE=InnoDB AUTO_INCREMENT=1168466 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE TABLE `m_device` ( `id` int NOT NULL AUTO_INCREMENT, `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '仪器类型', `number` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '仪器编号', `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '仪器名称', `organization` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '机构', `dealer` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '经销商', `area` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '区县', `engineer_id` int DEFAULT NULL COMMENT '工程师id', `update_date` datetime DEFAULT NULL, `maintain_date` datetime DEFAULT NULL COMMENT '保养时间', `dealer_id` int DEFAULT NULL COMMENT '经销商id', `organization_id` int DEFAULT NULL COMMENT '机构id', `socket_heart_last_time` datetime DEFAULT NULL COMMENT 'socket最后一次心跳时间', `flag` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '标志位,0:未填写地址;1:已填写地址', PRIMARY KEY (`id`) USING BTREE, KEY `fk_device` (`engineer_id`) USING BTREE, KEY `index_m_device_number` (`number`) USING BTREE, KEY `organization_id` (`organization_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=4615 DEFAULT CHARSET=utf8; CREATE TABLE `m_organization` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, `deleted_flag` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志', `dealer_id` int DEFAULT NULL COMMENT '经销商id', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=10066 DEFAULT CHARSET=utf8;
其中log_device_heart大概200w条数据,其它表都在200条左右
这是实际业务中的查询条件,这个项目是后续接手的,所以是不熟悉的Java项目
<select id="findDeviceHeartList" resultType="com.egs.biz.entity.vo.rsp.DeviceLogRsp$HeartRsp" parameterType="com.egs.biz.entity.vo.req.DeviceLogReq"> SELECT t3.`name` as orgName,t1.num,t1.other_num as otherNum, t1.device_number as deviceNumber,t1.time_periods_begin as timePeriodsBeginStr, t1.time_periods_end as timePeriodsEndStr,t1.create_time as createTimeStr,t1.date as updateTimeStr FROM log_device_heart t1 FORCE INDEX (time_periods_begin_desc) left join m_device t2 on t1.device_number=t2.number left join m_organization t3 on t3.id=t2.organization_id WHERE 1=1 <if test="heartReq.organization!=null and heartReq.organization!=''"> and t3.`name` like '%${heartReq.organization}%' </if> <if test="heartReq.dataCleanFlag==true"> and organization_id<>'10007' and organization not like '%测试机器%' </if> <if test="heartReq.deviceNumber!=null and heartReq.deviceNumber!=''"> and t1.device_number=#{heartReq.deviceNumber} </if> <if test="heartReq.heart4GNum!=null and heartReq.heart4GNum!=''"> and t1.num < #{heartReq.heart4GNum} </if> <if test="heartReq.startDate!=null"> and t1.time_periods_begin >= DATE_FORMAT(#{heartReq.startDate},'%Y-%m-%d 00:00:00') </if> <if test="heartReq.endDate!=null"> and t1.time_periods_begin <= DATE_FORMAT(#{heartReq.endDate},'%Y-%m-%d 23:59:59') </if> order by t1.time_periods_begin desc </select>
1 常规查询写法分析
select t3.`name` as orgName,t1.num,t1.other_num as otherNum, t1.device_number AS deviceNumber, t1.time_periods_begin AS timePeriodsBeginStr, t1.time_periods_end AS timePeriodsEndStr, t1.create_time AS createTimeStr, t1.date AS updateTimeStr FROM log_device_heart t1 -- use index(time_periods_begin_desc) STRAIGHT_JOIN m_device t2 ON t1.device_number = t2.number LEFT JOIN m_organization t3 ON t3.id = t2.organization_id WHERE 1 = 1 ORDER BY t1.time_periods_begin DESC LIMIT 10;
查询耗时3秒左右,查询计划显示驱动表并没有走索引,
200多w的主表数据,显然是无法接受这个结果的.
于是加上force index
SELECT t3.`name` AS orgName, t1.num, t1.other_num AS otherNum, t1.device_number AS deviceNumber, t1.time_periods_begin AS timePeriodsBeginStr, t1.time_periods_end AS timePeriodsEndStr, t1.create_time AS createTimeStr, t1.date AS updateTimeStr FROM log_device_heart t1 force INDEX ( time_periods_begin_desc ) LEFT JOIN m_device t2 ON t1.device_number = t2.number LEFT JOIN m_organization t3 ON t3.id = t2.organization_id WHERE 1 = 1 ORDER BY t1.time_periods_begin DESC LIMIT 10 > OK > 时间: 0.001s
查询耗时可以忽略,提升了1000多倍.
但这会带来另一个问题,当我where条件添加筛选的时候,强制索引会导致效率降低,如下:
SELECT t3.`name` AS orgName, t1.num, t1.other_num AS otherNum, t1.device_number AS deviceNumber, t1.time_periods_begin AS timePeriodsBeginStr, t1.time_periods_end AS timePeriodsEndStr, t1.create_time AS createTimeStr, t1.date AS updateTimeStr FROM log_device_heart t1 force INDEX ( time_periods_begin_desc ) LEFT JOIN m_device t2 ON t1.device_number = t2.number LEFT JOIN m_organization t3 ON t3.id = t2.organization_id WHERE 1 = 1 -- and t1.device_number='MDA20122110039' --该查询性能正常 and t3.`name`='xxx医院' ORDER BY t1.time_periods_begin DESC LIMIT 10;
该查询耗时0.6秒,已经较慢了.
查看查询计划,优化成了t3作为驱动表了,
那么根据情况,把,left join 改成straight_join
SELECT t3.`name` as orgName,t1.num,t1.other_num as otherNum, t1.device_number as deviceNumber,t1.time_periods_begin as timePeriodsBeginStr, t1.time_periods_end as timePeriodsEndStr,t1.create_time as createTimeStr,t1.date as updateTimeStr FROM log_device_heart t1 -- use index(time_periods_begin_desc) STRAIGHT_JOIN m_device t2 on t1.device_number=t2.number left join m_organization t3 on t3.id=t2.organization_id WHERE 1=1 and t1.device_number='MDA20123010006' and t3.`name`='xxx医院' -- and organization_id<>'10007' and organization not like '%学术机%' order by t1.time_periods_begin desc limit 100;
改成这样子,速度变成0.009秒.
查询计划也正常了
STRAIGH_JOIN会有两个问题,本质上更类似于inner join,不过这边对我的逻辑影响不大
第二个就是当查询结果匹配不到,会奇慢无比.大概耗时10秒左右.
目前尚未有更好的解决方法.
标签:多表,id,MySQL,t1,periods,time,device,NULL,order From: https://www.cnblogs.com/MarsPanda/p/17865055.html