explain工具 索引优化介绍

一 explain中的列

CREATE TABLE `actor` (
  `id` int(11) NOT NULL,
  `name` varchar(45) DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4


CREATE TABLE `film` (
  `id` int(11) NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4




CREATE TABLE `film_actor` (
  `id` int(11) NOT NULL,
  `film_id` int(11) DEFAULT NULL,
  `actor_id` int(11) DEFAULT NULL,
  `remark` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_film_actor_id` (`film_id`,`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

  • id是select 的编号,id的值越大,越先执行,id相同则从上往下执行,id为null最后执行(如果该行引用其他行的结果)
  • select_type 表示查询的类型
类型 涵义
simple 简单查询,没有包含子查询和union
primay 复杂查询的最外层查询
subquery 包含在select 种的子查询(不在from子句中)
derived 包含在from子句中的子查询。mysql会将结果存放在一个临时表中,也是派生表
  • table 列,输出行所指向的表名称,包含如下值
    1. <union M, N> : 行指向是id值为M和N的行的并集。
    2. : 行指向的是id值为N的派生表,在from 中的子查询

  • type 列,这一列表示关联类型或访问类型,即MySql决定如何查找表中的行,查找数据行记录的大概范围。接下来列举了描述连接类型,排序从好到差。

      1. system ,表中只有一行数据,是const连接类型的特列
      2. const  查询中只有一行匹配
      3. eq_ref: primary key或unique key索引的所有部分被连接使用,最多只会返回一条符合条件的记录。
      4. ref  :相比eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值比较,可能会找到很多符合条件的行。
      5. range :范围扫描,通常出现在in(),between,>,<等操作中,使用一个索引来检索给定的范围的行。
      6. index:全表扫描,使用了索引 ,也即是覆盖索引查询,
      7.  ALL:全表扫描,也就是mysql需要从头到尾区查找所需要的行。
    

    一般情况下,查询达到range级别,最好达到ref

  • possible_keys列,查询可能使用到的索引,但是不一定使用

  • key,mysql使用索引情况

  • key_len,显示Mysql在索引里使用的字节数,通过这值可以算出联合索引中使用了哪些索引

  • ref,显示在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名

  • rows,表明mysql执行查询必须检查的列,对于innodb,这个数字是估计值。

  • Extra列
    1. Using index:只使用索引树中的信息从表中检索列信息,而不必进行额外的查找来读取实际的行。
    2. Using index condition : 使用索引下推
    3. Using filesort:将用排序,而不是使用索引排序,数据较小时在内存排序,然后排序并检索行记录
    4. using temporary:使用到了临时表,主要发生在group by 和order by语句中。
    5. using where:WHERE子句用于限制哪些行匹配下一个表或发送给客户端。
    6. Select tables optimized away:使用了聚合函数,在查询期间不需要读取任何表,

二 索引使用注意点

  1. 最左前缀法则:如果索引使用了多列,要遵守最左前缀发法则。指是查询从索引的最左前列开始并且不跳过索引中的列。
  2. 不能在索引列上做计算,函数,类型转换,会导致索引失效而转向全表扫描
  3. 存储引擎不能使用索引中范围条件右边的列
  4. 尽量使用覆盖索引,减少select *语句
  5. mysql在使用不等于(!= <>)的时候无法使用索引会导致全表扫描
  6. is null,is not null这种无法使用索引
  7. like 使用通配符%索引失效会变成全表扫描操作
  8. 字符串不加单引号会导致索引失效
  9. 如果可以尽量不用or或者in,使用or,in的时候,mysql不一定会使用索引

like KK%相当于常量,%KK和%KK%相当于范围。

三 filesort 和index 排序

  • Mysql 支持两种方式的排序filesort 和 index,Using index 是指Mysql扫描索引本身完成排序。index效率高,filesort效率底。
  • order by 满足两种情况会使用Using index。
    1. order by 语句使用索引最左前列
    2. 使用where子句与order by子句条件列组合满足索引最左前列。
  • 尽量在索引列完成排序,遵循索引建立(索引创建顺序)时的最左前缀法则
  • 如果order by的条件不在索引列上,就会产生Using filesort
  • 能用覆盖索引尽量满足覆盖索引
  • group by与order by很类似,group by实质是先排序后分组,遵照索引创建顺序的最左前缀法则。对于group by的优化如果不需要排序的可以加上order by null 禁止排序。注意,where 高于having ,能写在where中的限定条件就不要去having 限定了。

Using file sort 文件排序方式

  • 单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;用trace工具就可以看到,如下图,sort_mode 信息中显示<sort_key,additional_fields>或者<sort_key,packed_additional_fields>
    在这里插入图片描述
  • 双路排序(又叫回表排序模式):是首先根据相应的条件取出相应的排序字段和可以直接定位行数据id,然后在sort buffer中进行排序,排序完后需要再次取回其他需要的字段;用trace工具可以看到sort_mode信息里显示<sort_key,rowid>

Mysql中可以通过比较系统变量max_length_for_sort_data(默认1024字节)的大小和需要查询的字段总大小来排队使用哪种排序模式

  • 如果max_length_for_sort_data比查询字段的总长度大,那么使用单路排序模式
  • 如果max_length_for_sort_data 比查询字段总长度小,那么使用双路排序模式

四 锁

mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性能底,开发中基本不会使用到。

  • 间隙锁在某些情况下可以解决幻读问题:
    update account set name =‘aaa’ where id>10 and id<=20;则其他Session没法在这个范围所包含的间隙中插入或修改任何数据

  • 无索引行锁会升级为表锁:锁主要是加在索引上,如果对非索引字段更新,行锁可能会变成表锁。InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则都会从行锁升级为表锁

-innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一下,但是在整体并发处理能力方面要远远优于MYISAM的表级锁定的。当系统并发量高的时候,Innodb的整体性能和MYISAM相比就会有比较明显的优势了。但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MYISAM高,甚至可能会更差。

通过检查 innodb_row_lock%,状态变量来分析系统上的行锁争夺情况

show status like’innodb_row_lock%’;

对各个状态量的说明如下:
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg: 每次等待所花平均时间
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits:系统启动后到现在总共等待的次数

记录锁: 对于唯一性的索引(包括唯一索引和主键索引)使用等值查询,精准匹配到了一条记录的时候,这个时候使用的就是记录锁。
间隙锁:左开右开
临键锁:左开右闭

优化建议

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
  • 合理设计索引,尽量缩小锁的范围
  • 尽可能减少检索条件范围,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
  • 尽可能低级别事务隔离

猜你喜欢

转载自blog.csdn.net/filling_l/article/details/112987587