1.问题
mysql单表数据量如果达到60多万,在一次使用mybatisPlus默认分页查询,默认查询当天的数据,该时间字段没有建立索引,根据时间范围查询姿势不对导致全表扫描,最终让接口调用超时,60w数据的磁盘好几个G了,超时时长设置为15s依然超时。
1.1 错误姿势
1.使用mybatisPlus提供的默认分页查询,时间字段没有走索引
select * from xxx 这种方式会导致全表扫描
2.表中字段是datetime类型,字段存在类型转换导致索引失效
mapper接口:
Page<PassRecordEntity> getPage(@Param("qryPageDTO") PassCarRecordPageDTO qryPageDTO, @Param("page") Page<PassRecordEntity> page);
mapper接口对应的xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxxx.dao.PassRecordDao">
<sql id="flieds">
id,
unique_no,
plate_no,
pass_time,
veh_type,
operator_name,
gate_name,
lane_name,
terminal_no,
lane_code,
card_no,
veh_color,
direction,
pass_Type,
parking_type,
plate_color,
total_region,
park_info,
veh_logo,
veh_logo_name,
in_pass_time,
in_unique_no,
should_pay,
actual_pay,
charge_type,
pic_file_path,
pic_plate_file_path,
pic_plate_file_data,
pic_vehicle_file_data,
pic_pilot_face_path,
pic_copilot_face_path,
pic_pilot_face_data,
pic_copilot_face_data,
dataType,
car_status,
car_owner,
car_owner_phone,
park_code,
park_name,
in_lane,
in_lane_id,
playing_lane,
playing_lane_id,
in_lane_time,
playing_lane_time,
parking_time,
in_lane_image,
playing_lane_image,
create_time,
update_time,
is_del,
remark
</sql>
<select id="getPage" parameterType="com.dytz.barrier.gate.entity.PassRecordEntity" resultType="com.dytz.barrier.gate.entity.PassRecordEntity">
SELECT
<include refid="flieds"></include>
-- 列出所需要的列,避免使用select *
FROM car_pass_record
where
is_del = 0
<if test="qryPageDTO.id != null ">
and id = #{qryPageDTO.id}
</if>
<if test="qryPageDTO.licensePlateNumber != null and qryPageDTO.licensePlateNumber.trim() neq '' ">
and plate_no = #{qryPageDTO.licensePlateNumber}
</if>
<if test="qryPageDTO.parkName != null and qryPageDTO.parkName.trim() neq '' ">
and park_name = #{qryPageDTO.parkName}
</if>
<if test="qryPageDTO.carStatus != null ">
and car_status = #{qryPageDTO.carStatus}
</if>
<if test="qryPageDTO.startTime != null and qryPageDTO.startTime.trim() neq ''
and qryPageDTO.endTime != null and qryPageDTO.endTime.trim() neq '' ">
<![CDATA[
and date_format (pass_time,'%Y-%m-%d %H:%i:%s') >= date_format(#{qryPageDTO.startTime},'%Y-%m-%d %H:%i:%s')
and date_format (pass_time,'%Y-%m-%d %H:%i:%s') <= date_format(#{qryPageDTO.endTime},'%Y-%m-%d %H:%i:%s')
]]>
-- pass_time该字段建立索引,但是字段存在类型转换会导致索引失效
</if>
ORDER BY id desc, create_time DESC
</select>
</mapper>
2.解决办法
2.1 自定mybatisPlus的分页查询
不使用select * from xx,列出需要的字段列select id, xx1,xx2,xxxxn from xxx, id是主键
2.2 表建立索引
在离散度高的子段上适当的建立索引,离散度高的意思是只每一列的区分度大适合建立索引(单列、联合…),比如:一列数据:0/1,男/女 这种列的离散度低,长得基本都很像,这种列就没有必要建立索引了,说白了也就是列的数据的区分度大不大,可以使用EXPLAIN查看sql的执行计划:type:ALL就是全表扫描,所以需要建立索引,优化查询速度和性能:
<![CDATA[
and date_format (pass_time,'%Y-%m-%d %H:%i:%s') >= date_format(#{qryPageDTO.startTime},'%Y-%m-%d %H:%i:%s')
and date_format (pass_time,'%Y-%m-%d %H:%i:%s') <= date_format(#{qryPageDTO.endTime},'%Y-%m-%d %H:%i:%s')
]]>
-- 将上面的方式改为如下方式:这种方式是可以命中索引的
<
被折叠的 条评论
为什么被折叠?



