高手回答

MySQL索引失效是一种常见问题,在处理慢查询时经常需要考虑索引失效的可能性。

针对索引失效的排查,关键步骤包括确定需要分析的SQL语句,并通过查看其执行计划。主要关注type、key和extra这几个字段。

SQL执行计划分析的时候,要关注哪些信息?

以下是一次返回的SQL语句执行计划的内容:

索引失效关键字_索引失效的几种情况_索引失效的

id:每个操作在执行计划中的唯一标识符。对于单条查询语句,每个操作具有独特的id。在多表连接时,多条记录的id会相同。

:操作的类型。常见类型包括、、、UNION等。不同类型的操作会影响查询效率。

table:当前操作涉及的表。

:当前操作涉及的分区。

type:表示查询时使用的索引类型,包括ALL、index、range、ref、、const等。

:可能被查询优化器选择使用的索引。

key:查询优化器选择使用的索引。

:索引的长度。较短的索引长度意味着更高的查询效率。

ref:指示用于与选择的索引列进行比较的列或常量。

rows:表示此操作需要扫描的行数,即扫描表中的行数以获取结果。

:表示操作过滤掉的行数占扫描行数的百分比。数值越大索引失效的几种情况,查询结果越精确。

Extra:提供额外信息,如Using index、Using 、Using 等。

假设我们拥有以下一张表(MySQL 5.7):


CREATE TABLE `t2` (
  `id` INT(11),
  `a` VARCHAR(64NOT NULL,
  `b` VARCHAR(64NOT NULL,
  `c` VARCHAR(64NOT NULL,
  `d` VARCHAR(64NOT NULL,
  `f` VARCHAR(64DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `f` (`f`),
  KEY `idx_abc` (`a``b``c`)
ENGINE=InnoDB DEFAULT CHARSET=latin1;

首先说起"type"字段,它具有以下几种取值以及它们之间的区别,我将为每种情况提供具体的SQL示例(请注意,以下SQL语句是我实际测试过的,但实际索引器可能会根据不同的数据和情况做出不同的优化):

explain select * from t2 where f='Paidaxing';

这里使用了唯一性索引进行唯一查询。

explain select * from t2 where f='Paidaxing';

在这种情况下,使用了唯一性索引进行唯一查询。

explain select * from t1 join t2 on t1.id = t2.id where t1.f = 's';

当在连接操作中使用了唯一索引或主键索引,并且连接条件是基于这些索引的等值条件时,MySQL通常会选择连接类型以提高查询性能。

explain select * from t2 where a = 'Paidaxing';

在这种情况下,使用了非唯一索引进行查询。

explain select * from t2 where a > 'a' and a < 'c';

在这里,使用了索引执行范围查询操作。

explain select c from t2 where b = 's';

这是一个不符合最左前缀匹配的查询示例。

explain select * from t2 where d = "ni";

这是一个使用非索引字段进行查询的示例。

需要注意的是,这里的"index"表示对索引树进行扫描,效率并不高。而以上类型的执行效率从快到慢依次为: > const > > ref > range > index > ALL。在谈到""和"key"时,""指出查询语句可能使用的索引,但不一定实际使用这些索引。该字段列出了可能用于该查询的所有索引,包括联合索引的组合。而"key"字段表示实际用于查询的索引。如果查询使用了索引,该字段将显示所使用的索引名称。

接下来谈到一个经常被忽视但非常重要的字段"extra",该字段描述了MySQL在执行查询时额外进行的一些操作。以下是"extra"可能的取值及其含义:

explain select * from t2 where d = "ni";   非索引字段查询
explain select d from t2 where b = "ni";   未索引覆盖,用联合索引的非前导列查询

explain select b, c from t2 where a = "ni";  索引覆盖

explain select d from t2 where a = "ni" and b like "s%";   使用到索引下推

explain select a from t2 where b = "ni";   索引覆盖,但不符合最左前缀
explain select b from t2 where a in ('a''d''sd');   索引覆盖,但前导列是一个范围

explain select * from t1 join t2 on t1.id = t2.id where a = 's';

explain select count(*), b from t2 group by b;

explain select count(*), b from t2 group by b; 

我们需要通过key+type+extra来判断一条SQL语句是否使用了索引。如果使用了索引,我们需要确定是覆盖索引、索引下推、还是整颗索引树的扫描,或者是索引跳跃扫描等情况。

一般来说,理想的情况应该是以下几种:

首先,key字段一定不能是NULL,必须有具体的值;其次,type字段应该是ref、、range、const等之一;另外,extra字段如果是NULL,或者是"using index"、"using index "都是符合条件的情况。

如果在执行计划中发现一条SQL语句没有使用到索引,比如type=ALL、key=NULL,以及extra=Using where,那就表示该查询未能利用索引。

在分析为什么一条SQL语句没有使用索引时,我们需要考虑到是否需要使用索引以及选择使用哪个索引是由MySQL的优化器决定的。优化器会根据成本估算做出这个决定。

以下是可能导致没有使用索引的几种情况:

索引未正确创建:如果查询语句中的where条件字段没有创建索引,或者不符合最左前缀匹配的情况,就是未正确创建索引。

索引区分度不高:索引的区分度不足可能导致不使用索引,因效率不高。

表过小:当表中数据很少索引失效的几种情况,优化器认为全表扫描成本不高时,也可能不使用索引。

查询中的索引字段使用了函数、类型不一致等导致索引失效。

针对这些情况,我们需要逐一分析:

如若索引未正确创建,根据SQL语句创建适当的索引。如果不符合最左前缀,调整索引或修改SQL语句。

若索引区分度低,考虑更换索引字段。

对于表很小的情况,影响可能不大,或许没有必要进行优化。

排查具体失效原因,然后根据情况调整SQL语句。

点击下方卡片进入公众号

即可阅读最新Java面试突击文章。非常优质的文章整理

免费分享无套路,有帮助点个赞就好!

如果想体验Chat GPT,也可关注以下公众号,也是免费无限使用。

好了,本章节到此告一段落。希望对你有所帮助,祝学习顺利。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注