Thresh
EXPLAIN
MySQL 提供了一个 EXPLAIN 命令,它能够对 SELECT 语句进行剖析,并输入 SELECT 执行的详细信息,供开发人员有针对性的优化。
EXPLAIN SELECT * from USERS where id >1 ;
select_type
示意查问的类型。罕用的值如下:
SIMPLE : 示意查问语句不蕴含子查问或unionPRIMARY:示意此查问是最外层的查问UNION:示意此查问是UNION的第二个或后续的查问EXPLAIN SELECT * from user WHERE id < 3;DEPENDENT UNION:UNION中的第二个或后续的查问语句,应用了里面查问后果UNION RESULT:UNION的后果SUBQUERY:SELECT子查问语句DEPENDENT SUBQUERY:SELECT子查问语句依赖外层查问的后果。
type
示意存储引擎查问数据时采纳的形式。比拟重要的一个属性,通过它能够判断出查问是全表扫描还是基于索引的局部扫描。罕用属性值如下,从上至下效率顺次加强。
ALL:示意全表扫描,性能最差。index:示意基于索引的全表扫描,先扫描索引再扫描全表数据。range:示意应用索引范畴查问。应用>、>=、<、<=、in等等。ref:示意应用非惟一索引进行单值查问。eq_ref:个别状况下呈现在多表join查问,示意后面表的每一个记录,都只能匹配前面表的一行后果。const:示意应用主键或惟一索引做等值查问,常量查问。NULL:示意不必拜访表,速度最快
possible_keys
示意查问时可能应用到的索引。留神并不一定会真正应用,显示的是索引名称。
key
示意查问时真正应用到的索引,显示的是索引名称。
rows
MySQL查问优化器会依据统计信息,估算SQL要查问到后果须要扫描多少行记录。原则上rows是越少效率越高,能够直观的理解到SQL效率高下。
key_len
示意查问应用了索引的字节数量。能够判断是否全副应用了组合索引。
key_len的计算规定如下:
字符串类型 字符串长度跟字符集无关:latin1=1、gbk=2、utf8=3、utf8mb4=4 char(n):n*字符集长度 varchar(n):n * 字符集长度 + 2字节 数值类型 TINYINT:1个字节 SMALLINT:2个字节 MEDIUMINT:3个字节 INT、FLOAT:4个字节 BIGINT、DOUBLE:8个字节 工夫类型 DATE:3个字节 TIMESTAMP:4个字节 DATETIME:8个字节 字段属性 NULL属性占用1个字节,如果一个字段设置了NOT NULL,则没有此项
Extra
Extra示意很多额定的信息,各种操作会在Extra提醒相干信息,常见几种如下:
Using where 示意查问须要通过索引回表查问数据。Using index 示意查问须要通过索引,索引就能够满足所需数据。Using filesort 示意查问进去的后果须要额定排序,数据量小在内存,大的话在磁盘,因而有Using filesort倡议优化。Using temprorary 查问应用到了长期表,个别呈现于去重、分组等操作。
回表查问
InnoDB索引有聚簇索引(主键索引)和辅助索引。聚簇索引的叶子节点存储行记录,InnoDB必须要有,且只有一个。辅助索引的叶子节点存储的是主键值和索引字段值,通过辅助索引无奈间接定位行记录,通常状况下,须要扫码两遍索引树。
先通过辅助索引定位主键值,而后再通过聚簇索引定位行记录,这就叫做回表查问,它的性能比扫一遍索引树低。
总结:通过索引查问主键值,而后再去聚簇索引查问记录信息
笼罩索引
即explain的输入后果Extra字段为Using index时,可能触发索引笼罩。
EXPLAIN SELECT e.* from EMPLOYEE e INNER JOIN COMPANY c on e.companyId = c.id
最左前缀准则
复合索引应用时遵循最左前缀准则,最左前缀顾名思义,就是最左优先,即查问中应用到最右边的列,那么查问就会应用到索引,如果从索引的第二列开始查找,索引将生效
CREATE TABLE `user2` ( `userid` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL DEFAULT '', `password` varchar(20) NOT NULL DEFAULT '', `usertype` varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (`userid`), KEY `a_b_c_index` (`username`,`password`,`usertype`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
当存在username时会应用索引查问:
explain select * from user2 where username = '1' and password = '1';
当没有username时,不会应用索引查问:
explain select * from user2 where password = '1';
LIKE查问
MySQL在应用like含糊查问时,索引能不能起作用?
MySQL在应用Like含糊查问时,索引是能够被应用的,只有把%字符写在前面才会应用到索引。
select * from user where name like '%o%'; //不起作用select * from user where name like 'o%'; //起作用select * from user where name like '%o'; //不起作用
NULL查问
如果MySQL表的某一列含有NULL值,那么蕴含该列的索引是否无效?
对MySQL来说,NULL是一个非凡的值,从概念上讲,NULL意味着“一个未知值”,它的解决形式与其余值有些不同。
比方:不能应用=,<,>这样的运算符,对NULL做算术运算的后果都是NULL,count时不会包含NULL行等,NULL比空字符串须要更多的存储空间等
NULL列须要减少额定空间来记录其值是否为NULL。对于MyISAM表,每一个空列额定占用一位,四舍五入到最靠近的字节。
尽管MySQL能够在含有NULL的列上应用索引,但NULL和其余数据还是有区别的,不倡议列上容许为NULL。最好设置NOT NULL,并给一个默认值,比方0和 ‘’ 空字符串等,如果是datetime类型,也能够设置零碎以后工夫或某个固定的非凡值,例如'1970-01-01 00:00:00'。
索引与排序
MySQL查问反对filesort和index两种形式的排序,filesort是先把后果查出,而后在缓存或磁盘进行排序操作,效率较低。应用index是指利用索引主动实现排序,不需另做排序操作,效率会比拟高。
filesort有两种排序算法:双路排序和单路排序。
- 双路排序:须要两次磁盘扫描读取,最终失去用户数据。第一次将排序字段读取进去,而后排序;第二次去读取其余字段数据。
- 单路排序:从磁盘查问所需的所有列数据,而后在内存排序将后果返回。如果查问数据超出缓存sort_buffer,会导致屡次磁盘读取操作,并创立长期表,最初产生了屡次IO,反而会减少累赘。
- 解决方案:少应用select *;减少sort_buffer_size容量max_length_for_sort_data容量。
如果咱们Explain剖析SQL,后果中Extra属性显示Using filesort,示意应用了filesort排序形式,须要优化。如果Extra属性显示Using index时,示意笼罩索引,也示意所有操作在索引上实现,也能够应用index排序形式,倡议大家尽可能采纳笼罩索引。
会应用index形式的排序
ORDER BY 子句索引列组合满足索引最左前列 explain select id from user order by id; //对应(id)、(id,name)索引无效WHERE子句+ORDER BY子句索引列组合满足索引最左前列 explain select id from user where age=18 order by name; //对应 (age,name)索引
会应用filesort形式的排序
对索引列同时应用了ASC和DESC explain select id from user order by age asc,name desc; //对应 (age,name)索引WHERE子句和ORDER BY子句满足最左前缀,但where子句应用了范畴查问(例如>、<、in等) explain select id from user where age>10 order by name; //对应 (age,name)索引ORDER BY或者WHERE+ORDER BY索引列没有满足索引最左前列 explain select id from user order by name; //对应(age,name)索引 应用了不同的索引,MySQL每次只采纳一个索引,ORDER BY波及了两个索引 explain select id from user order by name,age; //对应(name)、(age)两个索引WHERE子句与ORDER BY子句,应用了不同的索引 explain select id from user where name='tom' order by age; //对应 (name)、(age)索引WHERE子句或者ORDER BY子句中索引列应用了表达式,包含函数表达式 explain select id from user order by abs(age); //对应(age)索引