记录一次从小白开始的mysql调优(一)

由于所负责的项目数据量不太大,之前较少涉及到mysql调优

首先遇到了一个例子,领导给了一条sql过来要求优化,这个还是比较简单的

一、去掉多余的字段以及函数

select count(1) from (select 'abilityCert' as refType, src.ID as refId, src.NAME as name, urdp.DEPT_ID as deptId, src.USER_ID as userId, src.ATTACHMENTS as content, src.CREATE_TIME as createTime
         
          ,(select json_extract(state.STATE_INFO, '$.countView') from itlms_stat_state state where 'abilityCert' = state.REF_TYPE and src.id = state.REF_ID )countView
         
        from itlms_pinfo_material src
        join ipanther_user_dept urdp on urdp.IS_DELETED = 'N' and src.USER_ID = urdp.USER_ID
         
          
        where src.IS_DELETED = 'N' and src.ATTACHMENTS>'' and src.type ='1' 
         
            and not exists(select 1 from itlms_promote_reply where IS_DELETED = 'N' and CODE ='abilityCert' and REF_ID = src.id and USER_ID = 'yj_18039') limit 1000
                                                
                                                ) tmp_count;

查询的速度171ms
请添加图片描述

这里由于有许多多余的字段,于是就把他去掉了,另外exists函数会导致非常慢,所以用了not in 来代替
修改后如下

select
        count(1)
from
        (
        select
                1
        from
                itlms_pinfo_material src
        join ipanther_user_dept urdp on
                urdp.IS_DELETED = 'N'
                and src.USER_ID = urdp.USER_ID
        where
                src.IS_DELETED = 'N'
                and src.ATTACHMENTS>''
                and src.type = '1'
                and src.id not in (
                        select ref_id from itlms_promote_reply
                        where is_deleted='N'
                        and CODE = 'abilityCert'
                        and USER_ID = 'yj_18039'
                )
        limit 1000
                                                
                                                ) tmp_count;

修改后的查询速度
请添加图片描述

后面查得知,in还是有局限性的,只能限定1000条数据。所以遇到大数据量还需要别的办法

二、回表导致的索引失效问题

然后接着收到了第二条需要优化的sql
一开始看到的时候还是挺懵的。执行整整执行了36秒
先上sql

SELECT
        count( 1 ) 
FROM
        (
        SELECT
                t.* 
        FROM
                (
                SELECT
                        register.id,
                        'face' CODE,
                        register.user_id,
                        iud.dept_id,
                        IU.REAL_NAME,
                        IUT.TEACHER_NO,
                        IU.MOBILE_PHONE,
                        TRAIN.NAME TRAIN_NAME,
                        train.HOURS,
                        train.TRAIN_STAGE AS TRAIN_TRAIN_STAGE,
                        train.SUBJECT_CATEGORY,
                        TRAIN.TEACH_ADDRESS,
                        TRAIN.COURSE_TYPE,
                        REGISTER.AUDIT_RESULT,
                        REGISTER.AUDIT_STATUS,
                        REGISTER.AUDIT_REMARK,
                        classroom.TEACH_DATE AS class_date,
                        classroom.TEACH_TIME AS class_time,
                        '02' AS is_replenish 
                FROM
                        itlms_train_face_register register
                        JOIN ipanther_user_teacher iut ON register.user_id = iut.user_id 
                        AND iut.is_deleted = 'N'
                        JOIN ipanther_user iu ON iut.user_id = iu.id 
                        AND iu.is_deleted = 'N'
                        JOIN ipanther_user_dept iud ON iu.id = iud.user_id 
                        AND iud.is_deleted = 'N'
                        JOIN ipanther_department ide ON iud.dept_id = ide.id 
                        AND ide.is_deleted = 'N'
                        JOIN itlms_train_face_train train ON register.train_id = train.id 
                        AND train.is_deleted = 'N'
                        LEFT JOIN itlms_train_face_classroom classroom ON classroom.ID = register.CLASSROOM_ID 
                        AND classroom.is_deleted = 'N' 
                WHERE
                        register.is_deleted = 'N' 
                        AND train.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
                        AND train.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 
                        AND ((
                                        register.audit_status = '02' 
                                        AND register.dept_id = 'yj_1274' 
                                        ) 
                        OR ( register.audit_status = '01' AND ide.id = 'yj_1274' )) 
                        AND register.audit_status = '01' 
                        AND ( register.audit_result IS NULL OR register.audit_result = '' ) UNION ALL
                SELECT
                        register.id,
                        'online' CODE,
                        register.user_id,
                        iud.dept_id,
                        IU.REAL_NAME,
                        IUT.TEACHER_NO,
                        IU.MOBILE_PHONE,
                        TRAIN.NAME TRAIN_NAME,
                        train.HOURS,
                        train.TRAIN_STAGE AS TRAIN_TRAIN_STAGE,
                        train.SUBJECT_CATEGORY,
                        '' TEACH_ADDRESS,
                        TRAIN.COURSE_TYPE,
                        REGISTER.AUDIT_RESULT,
                        REGISTER.AUDIT_STATUS,
                        REGISTER.AUDIT_REMARK,
                        classroom.teach_time_start AS class_date,
                        classroom.teach_time_end AS class_time,
                        train.is_replenish AS is_replenish 
                FROM
                        itlms_train_online_register register
                        JOIN ipanther_user_teacher iut ON register.user_id = iut.user_id 
                        AND iut.is_deleted = 'N'
                        JOIN ipanther_user iu ON iut.user_id = iu.id 
                        AND iu.is_deleted = 'N'
                        JOIN ipanther_user_dept iud ON iu.id = iud.user_id 
                        AND iud.is_deleted = 'N'
                        JOIN ipanther_department ide ON iud.dept_id = ide.id 
                        AND ide.is_deleted = 'N'
                        JOIN itlms_train_online_train train ON register.train_id = train.id 
                        AND train.is_deleted = 'N'
                        LEFT JOIN itlms_train_online_classroom classroom ON register.classroom_id = classroom.id 
                        AND classroom.is_deleted = 'N' 
                WHERE
                        register.is_deleted = 'N' 
                        AND train.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
                        AND train.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 
                        AND ((
                                        register.audit_status = '02' 
                                        AND register.dept_id = 'yj_1274' 
                                        ) 
                        OR ( register.audit_status = '01' AND ide.id = 'yj_1274' )) 
                        AND register.audit_status = '01' 
                        AND ( register.audit_result IS NULL OR register.audit_result = '' ) 
                ) t 
        ORDER BY
                t.is_replenish,
                t.audit_status,
        t.user_id 
        ) t;

可以看到,即union all 了数据,每个union的表里都join了很多个表,那么该怎么解决呢?
首先由于使用了union all 不好知道是哪部分出了问题,于是考虑每个union all的数据单独执行一遍,于是把union all里的sql拆成两部分单独执行,发现了问题出在下部分,这里直接上下部分的

 SELECT
                        register.id,
                        'online' CODE,
                        register.user_id,
                        iud.dept_id,
                        IU.REAL_NAME,
                        IUT.TEACHER_NO,
                        IU.MOBILE_PHONE,
                        TRAIN.NAME TRAIN_NAME,
                        train.HOURS,
                        train.TRAIN_STAGE AS TRAIN_TRAIN_STAGE,
                        train.SUBJECT_CATEGORY,
                        '' TEACH_ADDRESS,
                        TRAIN.COURSE_TYPE,
                        REGISTER.AUDIT_RESULT,
                        REGISTER.AUDIT_STATUS,
                        REGISTER.AUDIT_REMARK,
                        classroom.teach_time_start AS class_date,
                        classroom.teach_time_end AS class_time,
                        train.is_replenish AS is_replenish 
                FROM
                        itlms_train_online_register register
                        JOIN ipanther_user_teacher iut ON register.user_id = iut.user_id 
                        AND iut.is_deleted = 'N'
                        JOIN ipanther_user iu ON iut.user_id = iu.id 
                        AND iu.is_deleted = 'N'
                        JOIN ipanther_user_dept iud ON iu.id = iud.user_id 
                        AND iud.is_deleted = 'N'
                        JOIN ipanther_department ide ON iud.dept_id = ide.id 
                        AND ide.is_deleted = 'N'
                        JOIN itlms_train_online_train train ON register.train_id = train.id 
                        AND train.is_deleted = 'N'
                        LEFT JOIN itlms_train_online_classroom classroom ON register.classroom_id = classroom.id 
                        AND classroom.is_deleted = 'N' 
                WHERE
                        register.is_deleted = 'N' 
                        AND train.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
                        AND train.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 
                        AND ((
                                        register.audit_status = '02' 
                                        AND register.dept_id = 'yj_1274' 
                                        ) 
                        OR ( register.audit_status = '01' AND ide.id = 'yj_1274' )) 
                        AND register.audit_status = '01' 
                        AND ( register.audit_result IS NULL OR register.audit_result = '' ) 

就是这条sql执行的非常慢,30多秒的时间基本都在这里耗尽了,为什么呢?
通过领导得知,此处由于from 表里的itlms_train_online_register 数据量很庞大,有1个多g,个人查了下有百万条数据了
请添加图片描述
然后走了很多弯路,先把where 里的join表查询条件给扔回join里面去(网上看到一种说法:最后过滤的数据量会更小)

-- 修改前
JOIN itlms_train_online_train train ON register.train_id = train.id 
AND train.is_deleted = 'N'
                        LEFT JOIN itlms_train_online_classroom classroom ON ...
-- 修改后
  JOIN itlms_train_online_train train ON register.train_id = train.id 
                        AND train.is_deleted = 'N'
                        AND train.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
                        AND train.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 

没发现执行效率上有显著差别

然后将每个join表分别去掉,看看会不会发现什么,结果还真发现了问题
还是这个表,把以下这个join表去掉后,效率有明显提升

-- 去掉的
 JOIN itlms_train_online_train train ON register.train_id = train.id 
                        AND train.is_deleted = 'N'

-- 修改后
SELECT
		            register.id,
		            'online' CODE,
		            register.user_id,
		            iud.dept_id,
		            IU.REAL_NAME,
		            IUT.TEACHER_NO,
		            IU.MOBILE_PHONE,
		--             TRAIN.NAME TRAIN_NAME,
		--             train.HOURS,
		--             train.TRAIN_STAGE AS TRAIN_TRAIN_STAGE,
		--             train.SUBJECT_CATEGORY,
		            
		            null as train_name,
		            null as hours,
		            null as TRAIN_TRAIN_STAGE,
		            null as SUBJECT_CATEGORY,
		            '' TEACH_ADDRESS,
		--             TRAIN.COURSE_TYPE,
		            null as COURSE_TYPE,
		            REGISTER.AUDIT_RESULT,
		            REGISTER.AUDIT_STATUS,
		            REGISTER.AUDIT_REMARK,
		            classroom.teach_time_start AS class_date,
		            classroom.teach_time_end AS class_time,
		            null as is_replenish
		--             train.is_replenish AS is_replenish 
		    FROM
		            itlms_train_online_register register
		            JOIN ipanther_user_teacher iut ON register.user_id = iut.user_id 
		            AND iut.is_deleted = 'N'
		            JOIN ipanther_user iu ON iut.user_id = iu.id 
		            AND iu.is_deleted = 'N'
		            JOIN ipanther_user_dept iud ON iu.id = iud.user_id 
		            AND iud.is_deleted = 'N'
		            JOIN ipanther_department ide ON iud.dept_id = ide.id 
		            AND ide.is_deleted = 'N'
		--             JOIN itlms_train_online_train train ON train.id  =register.train_id  
		--             AND train.is_deleted = "N"
		--             and train.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
		--             and train.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 
		            LEFT JOIN itlms_train_online_classroom classroom ON register.classroom_id = classroom.id 
		            AND classroom.is_deleted = 'N' 
		    WHERE
		            register.is_deleted = 'N' 
		            AND register.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
		            AND register.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 
		            AND ((
		                            register.audit_status = '02' 
		                            AND register.dept_id = 'yj_1274' 
		                            ) 
		            OR ( register.audit_status = '01' AND ide.id = 'yj_1274' )) 
		            AND register.audit_status = '01' 
		            AND ( register.audit_result IS NULL OR register.audit_result = '' ) 

这是为什么捏?
于是开始执行explain查看原因
这是去掉join之前的
注意这两个表,查了下type,possibleKey,key和keyLen所表示的意思,具体不写了百度很多地方查得到
其中留意到possibleKey和key,一个指的可能使用到的索引,一个指的实际使用的索引
请添加图片描述
保留itlms_train_online_train 发现register表仅仅使用了一个索引

把join itlms_train_online_train去掉,发现实际使用的索引变多了
请添加图片描述
这是为什么呢?
再看下两者后边的字段
去掉join前,而且指的留意的是,使用了join后,ref会变另一个表的id,此时触发回表
请添加图片描述
去掉join后
请添加图片描述
在extra中看到了明显的不同,其中加入了join表之后,就会变成using where,进行where过滤了。

由于二级索引连的是另一个表的主键,所以触发了回表
mysql引擎在执行sql前,会自己计算一套算法,去选择使用索引或者不使用索引
在回表数据量大的时候,可能会出现mysql觉得回表代价过大而乱用索引了
所以索引失效了

修改,使用关键字force index()强制使用索引

   SELECT
                        register.id,
                        'online' CODE,
                        register.user_id,
                        iud.dept_id,
                        IU.REAL_NAME,
                        IUT.TEACHER_NO,
                        IU.MOBILE_PHONE,
                        TRAIN.NAME TRAIN_NAME,
                        train.HOURS,
                        train.TRAIN_STAGE AS TRAIN_TRAIN_STAGE,
                        train.SUBJECT_CATEGORY,
                        '' TEACH_ADDRESS,
                        TRAIN.COURSE_TYPE,
                        REGISTER.AUDIT_RESULT,
                        REGISTER.AUDIT_STATUS,
                        REGISTER.AUDIT_REMARK,
                        classroom.teach_time_start AS class_date,
                        classroom.teach_time_end AS class_time,
                        train.is_replenish AS is_replenish 
                FROM
                        itlms_train_online_register register
                        force index(IDX_itlms_train_online_register_AUDIT_STATUS)
			             force index(IDX_itlms_train_online_register_TERM)
			              force index(IDX_itlms_train_online_register_YEAR)
			               force index(IDX_itlms_train_online_register_IS_DELETED)
                        JOIN ipanther_user_teacher iut ON register.user_id = iut.user_id 
                        AND iut.is_deleted = 'N'
                        JOIN ipanther_user iu ON iut.user_id = iu.id 
                        AND iu.is_deleted = 'N'
                        JOIN ipanther_user_dept iud ON iu.id = iud.user_id 
                        AND iud.is_deleted = 'N'
                        JOIN ipanther_department ide ON iud.dept_id = ide.id 
                        AND ide.is_deleted = 'N'
                        JOIN itlms_train_online_train train ON register.train_id = train.id 
                        AND train.is_deleted = 'N'
                        AND train.YEAR = '8a855a311b3b4e8f85c858188ce0469b' 
                        AND train.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' 
                        LEFT JOIN itlms_train_online_classroom classroom ON register.classroom_id = classroom.id 
                        AND classroom.is_deleted = 'N' 
                WHERE
                        register.is_deleted = 'N' 
                        AND ((
                                        register.audit_status = '02' 
                                        AND register.dept_id = 'yj_1274' 
                                        ) 
                        OR ( register.audit_status = '01' AND ide.id = 'yj_1274' )) 
                        AND register.audit_status = '01' 
                        AND ( register.audit_result IS NULL OR register.audit_result = '' ) 

速度变为了1.89秒
在这里插入图片描述
成功优化

三、子函数做字段,留意其查询条件

先上原来的sql

 select
	t.*,
	(t.classroom_teacher_num-t.register_valid_count) rest_count
from
	(
	select
		train.id,
		train.regist_time_start regist_time_start,
		train.regist_time_end regist_time_end,
		train.course_id course_id,
		train.resource_id resource_id,
		train.train_ids train_ids,
		classroom.id classroom_id,
		classroom.is_add is_add,
		train.name name,
		train.course_type course_type,
		train.teacher_name teacher_name,
		train.teacher_link_phone teacher_link_phone,
		iu.real_name incharge_teacher_name,
		iu.office_phone incharge_teacher_link_phone,
		classroom.submit_work_time_end submit_work_time_end,
		classroom.teach_time_start teach_time_start,
		classroom.teach_time_end teach_time_end,
		train.classroom_teacher_num classroom_teacher_num,
		train.teach_subjects teach_subjects,
		train.subject_category subject_category,
		train.hours hours,
		train.is_replenish is_replenish,
		regist.id register_id,
		regist.audit_status register_audit_status,
		regist.audit_result register_audit_result,
		/*(select count(1) from itlms_train_online_register re where re.train_id = train.id and re.classroom_id = classroom.id AND re.is_deleted='N') register_count,*/
		(
		select
			count(1)
		from
			itlms_train_online_register reg
		where
			reg.train_id = train.id
			and reg.classroom_id = classroom.id
			and reg.is_deleted = 'N'
			and (reg.audit_result is null
				or reg.audit_result != '02')) register_valid_count,
		classroom.status classroom_status,
		train.term term,
		train.IS_TOP IS_TOP,
		train.train_stage,
		(
		select
			count(1)
		from
			itlms_score_temp1 sc
		where
			sc.resource_id = train.resource_id
			and sc.score > 0
			and sc.code = 'online'
			and sc.user_id = '20751CDF73D60A5CE050A8C0030145CA' ) year_register_count,
		(
		select
			resource.RESOURCE_QUALITY
		from
			itlms_online_resource resource
		where
			resource.is_deleted = 'N'
			and resource .id = train.resource_id) RESOURCE_QUALITY
	from
		itlms_train_online_train train
	join itlms_train_online_train_classroom tc on
		train.id = tc.train_id
	join itlms_train_online_classroom classroom on
		classroom.id = tc.classroom_id
		and classroom.is_deleted = 'N'
	left join ipanther_user iu on
		train.incharge_teacher_id = iu.id
		and iu.is_deleted = 'N'
	left join itlms_train_online_register regist on
		train.id = train.id
		and regist.classroom_id = classroom.id
		and regist.is_deleted = 'N'
		and regist.user_id = '20751CDF73D60A5CE050A8C0030145CA'
	where
		train.is_deleted = 'N'
		and train.audit_result = '01'
		and train.status = '01'
		and train.is_resource = '02'
		and train.year = '8a855a311b3b4e8f85c858188ce0469b'
		and (train.train_stage in ('X', 'Z', 'G', 'Q', 'ZX' , 'PR', 'JM', 'SM', 'VH', 'PR-JM-SM', 'COMMON', 'TK', 'SSZT')
			or train.train_stage is null
			or train.train_stage = '') ) t
order by
	t.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' desc,
	t.is_top desc,
	t.course_type = 'SP' desc,
	t.is_replenish asc,
	rest_count desc,
	t.RESOURCE_QUALITY = '01' desc

执行下时间,发现是1.4秒
看到这条sql,就能想到很可能是子查询register_valid_count或者是year_register_count两者之一出现了问题,由于两者都是在列上进行子查询的,也就是from itlms_train_online_train 加上若干个join之后得到的一条数据,都会子查询一次register_valid_count和子查询一次year_register_count
一条记录就查一次子查询。很可能是两个之中的一个出现了问题。

将register_valid_count注释掉后发现速度明显的变快了,所以判断是register_valid_count的问题。
然后发现后面已经inner join itlms_train_online_classroom 表了,而register_valid_count还有

where
			reg.train_id = train.id
			and reg.classroom_id = classroom.id

这里有一次重复,吧其中的class_room_id给注释掉。发现变快了

		(
		select
			count(*)
		from
			itlms_train_online_register reg 
		where
			reg.train_id = train.id
			-- and reg.classroom_id = classroom.id
			and reg.is_deleted = 'N'
 			and (reg.audit_result is null
 				or reg.audit_result != '02')
				) register_valid_count,

这里讲一个题外话,mysql官方推荐使用count(星*)作为count的功能,虽然count(1)和count(星*)功能是一样的,但是官方写法推荐为count(星*)。
count(星*)会包括null元素而count(列)不会包含null元素
所以此处先把classroom_id给去掉,完成初步优化。此时快了一点但是不明显,接下来到进一步优化了

 select
	t.*,
	(t.classroom_teacher_num-t.register_valid_count) rest_count
from
	(
	select
		train.id,
		train.regist_time_start regist_time_start,
		train.regist_time_end regist_time_end,
		train.course_id course_id,
		train.resource_id resource_id,
		train.train_ids train_ids,
		classroom.id classroom_id,
		classroom.is_add is_add,
		train.name name,
		train.course_type course_type,
		train.teacher_name teacher_name,
		train.teacher_link_phone teacher_link_phone,
		iu.real_name incharge_teacher_name,
		iu.office_phone incharge_teacher_link_phone,
		classroom.submit_work_time_end submit_work_time_end,
		classroom.teach_time_start teach_time_start,
		classroom.teach_time_end teach_time_end,
		train.classroom_teacher_num classroom_teacher_num,
		train.teach_subjects teach_subjects,
		train.subject_category subject_category,
		train.hours hours,
		train.is_replenish is_replenish,
		regist.id register_id,
		regist.audit_status register_audit_status,
		regist.audit_result register_audit_result,
		/*(select count(1) from itlms_train_online_register re where re.train_id = train.id and re.classroom_id = classroom.id AND re.is_deleted='N') register_count,*/
		(
		select
			count(1)
		from
			itlms_train_online_register reg
		where
			reg.train_id = train.id
			-- 注释此处
			-- and reg.classroom_id = classroom.id
			and reg.is_deleted = 'N'
			and (reg.audit_result is null
				or reg.audit_result != '02')) register_valid_count,
		classroom.status classroom_status,
		train.term term,
		train.IS_TOP IS_TOP,
		train.train_stage,
		(
		select
			count(1)
		from
			itlms_score_temp1 sc
		where
			sc.resource_id = train.resource_id
			and sc.score > 0
			and sc.code = 'online'
			and sc.user_id = '20751CDF73D60A5CE050A8C0030145CA' ) year_register_count,
		(
		select
			resource.RESOURCE_QUALITY
		from
			itlms_online_resource resource
		where
			resource.is_deleted = 'N'
			and resource .id = train.resource_id) RESOURCE_QUALITY
	from
		itlms_train_online_train train
	join itlms_train_online_train_classroom tc on
		train.id = tc.train_id
	join itlms_train_online_classroom classroom on
		classroom.id = tc.classroom_id
		and classroom.is_deleted = 'N'
	left join ipanther_user iu on
		train.incharge_teacher_id = iu.id
		and iu.is_deleted = 'N'
	left join itlms_train_online_register regist on
		train.id = train.id
		and regist.classroom_id = classroom.id
		and regist.is_deleted = 'N'
		and regist.user_id = '20751CDF73D60A5CE050A8C0030145CA'
	where
		train.is_deleted = 'N'
		and train.audit_result = '01'
		and train.status = '01'
		and train.is_resource = '02'
		and train.year = '8a855a311b3b4e8f85c858188ce0469b'
		and (train.train_stage in ('X', 'Z', 'G', 'Q', 'ZX' , 'PR', 'JM', 'SM', 'VH', 'PR-JM-SM', 'COMMON', 'TK', 'SSZT')
			or train.train_stage is null
			or train.train_stage = '') ) t
order by
	t.term = 'ffd3f8bb2eb849abb2fb536f91a5dd8c' desc,
	t.is_top desc,
	t.course_type = 'SP' desc,
	t.is_replenish asc,
	rest_count desc,
	t.RESOURCE_QUALITY = '01' desc

走了很多弯路后,得出了进一步优化结果,使用联合索引

四、使用联合索引

为什么注释掉classroom_id会更快呢?
用explain关键字对比下两者,发现其中加了classroom_id之后的explain触发了回表
图1-0
请添加图片描述
而去掉之后则才会索引覆盖
图1-1
图1-1
为什么会这样呢?itlms_train_online_register 表中的索引包含了 train_id 和classroom_id 和 is_deleted ,这三个每个都是有单独索引的
请添加图片描述
由于mysql大多数情况下对每个表匹配索引都是匹配一个索引的,我们留意到图1-0和图1-1,每行的key都是仅有一个的,这是因为mysql每次使用索引都会用一个,用多个mysql计算的结果是更消耗时间(后面有例子,是使用了多个单独索引的 ),所以此处仅会使用一条。
执行以下,发现使用using where,触发了回表,但是实际上是使用了索引IDX_itlms_train_online_register_TRAIN_ID。使用了索引,但是触发了回表

explain select
			count(*)
		from
			itlms_train_online_register reg 
		where
			 reg.train_id = '0197ffc3b37f4d2e90dcefff5477b335'
			
		and reg.is_deleted = 'N'
			and (reg.audit_result is null
				or reg.audit_result != '02')
			and (reg.audit_result ='01'
				 or reg.audit_result ='02'
				)

请添加图片描述
执行explain后这句话表示什么呢?这句话就表示说:虽然你给3个字段单独添加了索引,他们也是可能使用的(最左边列为possible_key),但是实际上只使用了一个索引,也就是key为IDX_itlms_train_online_register_TRAIN_ID,其余的判断条件通过回表,再使用where 进行条件过滤
仅使用reg.tran_id的查询条件会发生什么呢?此时就会索引覆盖了

explain select
			count(*)
		from
			itlms_train_online_register reg 
		where
			 reg.train_id = '0197ffc3b37f4d2e90dcefff5477b335'
		

请添加图片描述
可以看到,extra里面就有using index了。
那么我们该如何去让多条件匹配也走索引呢?答案就是使用联合索引
使用联合索引,是最左匹配原则,遇到范围值则不会在匹配下一个索引条件(具体不解释了,此处只将结论)

我们对train_id ,audit_result ,is_deleted 按顺序建立联合索引
根据最左匹配原则,由于train_id此处是最容易匹配到的,所以放最左边,而audit_result有4个值,放中间,is_deleted只有两个值,所以放是最后

CREATE INDEX IDX_itlms_train_online_register_TRAIN_ID_AUDIT_RESULT_IS_DELETED USING BTREE ON itlms_zs.itlms_train_online_register (TRAIN_ID,AUDIT_RESULT,IS_DELETED);

再次explain第一条多条件的sql,发现已经走了索引了
请添加图片描述
所以在第三题的情况下优化,此时就会变快了(此处没有任何改动)

	.....	(
		select
			count(*)
		from
			itlms_train_online_register reg 
		where
			reg.train_id = train.id
			-- and reg.classroom_id = classroom.id
			and reg.is_deleted = 'N'
 			and (reg.audit_result is null
 				or reg.audit_result != '02')
				) register_valid_count,
				......

请添加图片描述
从1.4秒达到了370ms左右。优化成功

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值