在需要查询的Sql前加上‘EXPLAIN’即可。
示例
某条sql要联调查询4张表,分别为sys_user,sys_user_fs,explicit_number,sys_dept。
他们各自表的索引和字段如下
sys_user:
sys_user_fs:
explicit_number:
sys_dept:
现在我们执行这条sql语句,来看看用到了哪些索引。
EXPLAIN SELECT
u.user_id,
u.dept_id,
u.user_name,
u.real_name,
u.user_type,
u.user_seat_type,
u.staff_code,
u.crm_job_name AS crmJobName,
u.STATUS,
u.create_by,
u.create_time,
u.update_by,
u.update_time,
uf.explicit_number_id,
uf.explicit_number_id2,
uf.fs_status,
uf.seat_type,
uf.terminal_num,
SUBSTRING_INDEX( en.explicit_number, 'D5054',- 1 ) AS explicit_number,
SUBSTRING_INDEX( en2.explicit_number, 'D5054',- 1 ) AS explicit_number2,
d.dept_name AS crmDeptName
FROM
sys_user u
LEFT JOIN sys_user_fs uf ON u.user_id = uf.user_id
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
LEFT JOIN explicit_number en ON en.id = uf.explicit_number_id
LEFT JOIN explicit_number en2 ON en2.id = uf.explicit_number_id2
LEFT JOIN sys_user ucreate ON u.create_by = ucreate.user_name
WHERE
u.del_flag = '0'
AND u.user_type = '2'
ORDER BY
u.create_time DESC
LIMIT 10
根据显示的信息我们可以看到,'d’表(sys_dept),‘en’表(explicit_number),‘en2’表(explicit_number),‘ucreate’表(sys_user)用到了索引,因为他们的type字段结果为’eq_ref’及’ref’。
‘d’,‘en’,‘en2’的possible_keys字段结果为’PRIMARY’,所以用到的索引分别是主键索引;
‘ucreate’表用到的则是我们自定义的索引,possible_keys字段结果为’index_name’,意味着索引名就为’index_name’,该索引绑定了user_name这个字段。
而’u’表(sys_user)和’uf’表(sys_user_fs)的type字段结果为’ALL’,代表是查询了全部字段,也就是没有用到索引。
看了上面的分析后,问题就明了了。
在sql语句中,u(sys_user)和uf(sys_user_fs)这两张表是通过各自的user_id字段去连表查询来关联的。
但’u’(sys_user)表中的user_id字段虽然被绑定了索引,但是’uf’(sys_user_fs)表的user_id字段是没有绑定索引的。所以这条sql查询的慢。
解决方案
1.给uf(sys_user_fs)表的user_id字段绑定索引。
添加索引时,一定要根据该字段在查询语句中的顺序来添加,要注意先后索引字段的顺序。
2.给u(sys_user)表在WHERE查询时用到的字段绑定索引。
此处是根据该表在条件(WHERE)查询时所用到的字段,来绑定对应字段的索引,同样需要两者的顺序保持一致,也就是索引字段的顺序和WHERE条件中所用到的字段顺序要一致。
场景二:类型不匹配造成的索引失效(未走索引)
有时候很奇怪,明明涉及到的字段加了索引,顺序也一致,但是用EXPLAIN一看就是没走索引,这种情况多半是sql语句中和字段值,和其表中定义的字段类型不匹配造成的。
我们来看一下下面的这个sql语句,就是这个问题。
EXPLAIN SELECT
t1.id,
t1.workflow_process_id,
SUBSTRING_INDEX( t1.explicit_number, 'D5054',- 1 ) AS explicit_number,
t1.number_type,
t1.create_time,
t1.create_by,
t1.del_flag,
t1.dept_id,
t1.style,
t1.STATUS,
t1.fs_explicit_id,
t1.city_code,
t1.file_path,
d.dept_name AS org_name,
t3.opr_time,
CASE
WHEN t3.opr_result = - 1 THEN
'不通过'
WHEN t3.opr_result = 1 THEN
'通过'
WHEN t3.opr_result = 0 THEN
'审核中'
END AS opr_result
FROM
explicit_number t1
LEFT JOIN sys_dept d ON t1.dept_id = d.dept_id
LEFT JOIN workflow_process t3 ON t1.workflow_process_id = t3.id
LEFT JOIN sys_user u ON t1.create_by = u.user_name
WHERE
t1.del_flag = 0
and t1.create_time LIKE concat(left('2021-12-15 00:00:00', 10), '%')
通过表结构我们知道,t1(explicit_number)的’del_flag’字段是char类型,但sql语句中使用了 t1.del_flag = 0
,也就是判断字段值是否为整数型的0.而非为char字符的0.
所以del_flag字段值本身的类型为char字符类型,但却在sql语句中使用了整数型来判断它是否为0,这也就导致了索引未生效。
正确的用法是改为 t1.del_flag = '0'
正确的则是下面这样:
EXPLAIN SELECT
t1.id,
t1.workflow_process_id,
SUBSTRING_INDEX( t1.explicit_number, 'D5054',- 1 ) AS explicit_number,
t1.number_type,
t1.create_time,
t1.create_by,
t1.del_flag,
t1.dept_id,
t1.style,
t1.STATUS,
t1.fs_explicit_id,
t1.city_code,
t1.file_path,
d.dept_name AS org_name,
t3.opr_time,
CASE
WHEN t3.opr_result = - 1 THEN
'不通过'
WHEN t3.opr_result = 1 THEN
'通过'
WHEN t3.opr_result = 0 THEN
'审核中'
END AS opr_result
FROM
explicit_number t1
LEFT JOIN sys_dept d ON t1.dept_id = d.dept_id
LEFT JOIN workflow_process t3 ON t1.workflow_process_id = t3.id
LEFT JOIN sys_user u ON t1.create_by = u.user_name
WHERE
t1.del_flag = '0'
and t1.create_time LIKE concat(left('2021-12-15 00:00:00', 10), '%')
ORDER BY
t1.create_time DESC