什么是慢查询?
MySQL如何判断一个查询是否是慢查询,是通过将SQL的执行时间与long_query_time这个系统参数做比较,如果执行时间大于设置的系统参数,且开启了慢查询日志,那么MySQL就会将此查询记录到慢查询日志中。 long_query_time的默认时间是10s,生产环境中我们不会设置这么大的值。一般我们会设置为1s,对于一些对延迟比较敏感的业务会设置一个比1s还小的值。
如何判断语句是否使用了索引?
语句的执行过程中是否使用了表的索引,具体到表象中是explain一个语句的时候,看key这一栏是否为NULL。
但是要注意图2,图3的区别,如果说表的数据量特别的大,或者执行时CPU压力特别的大,select a from t 的执行时间也会超过long_query_time成为慢查询。
图3的执行只是表明sql查询时使用了遍历a索引树。
是否使用了索引与是否使用到了索引的快速定位功能的区别
是否使用了索引只是表示一个SQL语句的执行过程,是否记录慢查询是由它的执行时间决定的,而这个执行时间可能会受到各种外部因素的影响,也就是说是否使用索引和是否记录慢查询之间没有必然的联系。
什么叫做使用了索引
InnoDB是索引组织表,所有的数据都是存储在索引树上面的。
比如说这个表中包含了两个索引,一个是主键索引id,一个是普通索引a,在InnoDB里数据是放在主键索引里的。
如果从逻辑上说,所有的InnoDB表上的查询都至少会使用到一个索引。
从逻辑上说,你知道这个语句肯定是做了全表扫描,但优化器认为,这个语句的执行过程中需要根据主键索引,定位到第一个满足id>0的值,也算用到了索引。所以就算explain结果里写了key不是NULL,实际上可能是全表扫描的。
因此InnoDB里面只有一种情况叫做没有使用索引,从主键索引的最左边节点开始,向右扫描整个索引树,也就是说没有使用索引并不是一个准确的描述,你可以用全表扫描来表示来表示一个查询遍历了整个主键索引树,也可以用全索引扫描来说明像select a from t;这样的查询,它扫描了整个普通索引树。而像select * from t where id = 2;这样的查询语句,才是我们平时说的使用了索引。它表示的意思是,我们使用了索引的快速搜索功能,并且有效的减少了扫描行数。
使用了索引但是执行不够快的例子
索引的过滤性
查询全国人民,年龄在10-15岁之间的所有人的信息 select * from t_people where age between 10 and 15; 你一看这个语句一定要在age字段上建索引了,否则就是一个全表扫描,但是在你建了age上的索引以后,这个语句还是执行慢,因为满足这个条件的语句有超过1亿行。 当我们在讨论有没有使用索引的时候,其实我们关心的是扫描行数("排序也是一个考量因素,但是此处不展开")。 对于一个大表,不止要有索引,索引的过滤性还要足够好,像刚才的例子中age,它的过滤性就不够好,在设计表结构的时候,我们要让索引的过滤性足够好,也就是区分度足够高。
过滤性好了是不是表示查询的扫描行数一定少呢? 查询的过滤性与索引的过滤性可并不一定是一样的
回表,最左前缀原则,索引下推(5.6版本后) select * from t_people where name like '张%' and age = 10; mysql 5.7引入的虚拟列实现,具体修改表结构的语句 alter table t_people add name_first varchar(2) generated always as (left(name,1)),add index (name_first,age); 虚拟列是在插入时不指定值,在更新的时候也不能主动修改,它的值会根据定义自动生成。在name字段修改的时候也会自动修改。
原来的查询语句可以改为:
select * from t_people where name_first = '张' and age = 8;
使用索引的语句也可能是慢查询,我们查询优化的过程往往就是减少扫描行数的过程。
在此推荐极客时间上丁奇老师的专栏:MySQL实战45讲