真正线上索引失效的问题是如何排查的

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: MySQL索引失效是一种常见问题,在处理慢查询时经常需要考虑索引失效的可能性。针对索引失效的排查,关键步骤包括确定需要分析的SQL语句,并通过`EXPLAIN`查看其执行计划。主要关注`type`、`key`和`extra`这几个字段。

高手回答

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

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

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

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

  1. id:每个操作在执行计划中的唯一标识符。对于单条查询语句,每个操作具有独特的id。在多表连接时,多条记录的id会相同。
  2. select_type:操作的类型。常见类型包括SIMPLE、PRIMARY、SUBQUERY、UNION等。不同类型的操作会影响查询效率。
  3. table:当前操作涉及的表。
  4. partitions:当前操作涉及的分区。
  5. type:表示查询时使用的索引类型,包括ALL、index、range、ref、eq_ref、const等。
  6. possible_keys:可能被查询优化器选择使用的索引。
  7. key:查询优化器选择使用的索引。
  8. key_len:索引的长度。较短的索引长度意味着更高的查询效率。
  9. ref:指示用于与选择的索引列进行比较的列或常量。
  10. rows:表示此操作需要扫描的行数,即扫描表中的行数以获取结果。
  11. filtered:表示操作过滤掉的行数占扫描行数的百分比。数值越大,查询结果越精确。
  12. Extra:提供额外信息,如Using index、Using filesort、Using temporary等。

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


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

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

  • system:系统表,数据量较小,通常无需进行磁盘IO。
    explain select * from t2 where f='Paidaxing';
    

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

  • const:使用常量索引,MySQL在查询时只会使用常数值进行匹配。
    explain select * from t2 where f='Paidaxing';
    

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

  • eq_ref:唯一索引扫描,只会扫描索引树中的一个匹配行。
    explain select * from t1 join t2 on t1.id = t2.id where t1.f = 's';
    

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

  • ref:非唯一索引扫描,只会扫描索引树中的一部分来查找匹配的行。
    explain select * from t2 where a = 'Paidaxing';
    

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

  • range:范围扫描,只会扫描索引树中的一个范围来查找匹配的行。
    explain select * from t2 where a > 'a' and a < 'c';
    

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

  • index:全索引扫描,会遍历索引树来查找匹配的行。
    explain select c from t2 where b = 's';
    

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

  • ALL:全表扫描,将遍历整个表来找到匹配的行。
    explain select * from t2 where d = "ni";
    

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

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

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

  • Using where:表示MySQL在存储引擎检索行后,再进行条件过滤(使用WHERE子句)。查询的列未被索引覆盖,where筛选条件非索引的前导列或者where筛选条件非索引列。
explain select * from t2 where d = "ni";   非索引字段查询
explain select d from t2 where b = "ni";   未索引覆盖,用联合索引的非前导列查询
  • Using index:表示MySQL使用了覆盖索引(也称为索引覆盖)优化,只需扫描索引,而无需返回数据表中检索行。
explain select b, c from t2 where a = "ni";  索引覆盖
  • Using index condition:表示查询在索引上执行了部分条件过滤。这通常涉及索引下推。
explain select d from t2 where a = "ni" and b like "s%";   使用到索引下推
  • Using where; Using index:查询的列被索引覆盖,并且where筛选条件是索引列之一,但不是索引的前导列,或者where筛选条件是索引列前导列的一个范围。
explain select a from t2 where b = "ni";   索引覆盖,但不符合最左前缀
explain select b from t2 where a in ('a', 'd', 'sd');   索引覆盖,但前导列是一个范围
  • Using join buffer:表示MySQL使用连接缓存。
explain select * from t1 join t2 on t1.id = t2.id where a = 's';
  • Using temporary:表示MySQL创建了临时表来存储查询结果,通常在排序或分组时发生。
explain select count(*), b from t2 group by b;
  • Using filesort:表示MySQL将使用文件排序而不是索引排序,通常在无法使用索引进行排序时发生。
explain select count(*), b from t2 group by b;
  • Using index for group-by:表示MySQL在分组操作中使用了索引,通常在分组操作涉及索引中的所有列时发生。
  • Using filesort for group-by:表示MySQL在分组操作中使用了文件排序,通常在无法使用索引进行分组操作时发生。
  • Range checked for each record:表示MySQL在使用索引范围查找时,需要检查每一条记录。
  • Using index for order by:表示MySQL在排序操作中使用了索引,通常在排序涉及索引中的所有列时发生。
  • Using filesort for order by:表示MySQL在排序操作中使用了文件排序,通常在无法使用索引进行排序时发生。
  • Using index for group-by; Using index for order by:表示MySQL在分组和排序操作中都使用了索引。

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

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

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

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

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

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

  1. 索引未正确创建:如果查询语句中的where条件字段没有创建索引,或者不符合最左前缀匹配的情况,就是未正确创建索引。
  2. 索引区分度不高:索引的区分度不足可能导致不使用索引,因效率不高。
  3. 表过小:当表中数据很少,优化器认为全表扫描成本不高时,也可能不使用索引。
  4. 查询中的索引字段使用了函数、类型不一致等导致索引失效。

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

  1. 如若索引未正确创建,根据SQL语句创建适当的索引。如果不符合最左前缀,调整索引或修改SQL语句。
  2. 若索引区分度低,考虑更换索引字段。
  3. 对于表很小的情况,影响可能不大,或许没有必要进行优化。
  4. 排查具体失效原因,然后根据情况调整SQL语句。

如有问题,微信搜索【码上遇见你】。

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

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
SQL Oracle 关系型数据库
分析索引失效的几种情况
联合索引 is not null 只要在建立的索引列(不分先后)都会走, in null时 必须要和建立索引第一列一起使用,当建立索引第一位置条件是is null 时,其他建立索引的列可以是is null(但必须在所有列 都满足is null的时候),或者=一个值; 当建立索引的第一位置是=一个值时,其他索引列可以是任何情况(包括is null =一个值),以上两种情况索引都会走。其他情况不会走。
101 1
|
6月前
|
SQL Oracle 关系型数据库
索引失效的情况分析
大家都知道,一条查询语句走了索引和没走索引的查询效率是非常大的,在我们建好了表,建好了索引后,但是一些不好的sql会导致我们的索引失效,下面介绍一下索引失效的几种情况
43 0
|
4月前
|
Java 测试技术 API
面试题ES问题之零停机索引重建方案的选择如何解决
面试题ES问题之零停机索引重建方案的选择如何解决
29 0
|
SQL Arthas druid
MyBtais 批量插入慢排查及分析(后续)
MyBtais 批量插入慢排查及分析(后续)
184 0
|
SQL 关系型数据库 MySQL
mysql线上连接超时和字段过长排查思路
mysql线上连接超时和字段过长排查思路
|
运维 JavaScript 前端开发
记录两次多端排查问题的过程
记录两次多端排查问题的过程
|
数据库 索引
MysSQL索引会失效的几种情况分析
MysSQL索引会失效的几种情况分析
150 0
MysSQL索引会失效的几种情况分析
|
SQL 存储 前端开发
项目上线后我是如何通过慢查询和索引让系统快起来的
最近对mysql的操作比较多一些,主要是项目上线以后,难免会有一些数据上的问题。开始的时候还主要由后端来处理,后面数据问题确实比较多,于是我就找后端要来服务器的账号密码,连上数据库顺便来看看数据的问题。
132 0
|
存储 消息中间件 缓存
失效问题处理:业务分析以及资料介绍| 学习笔记
快速学习失效问题处理:业务分析以及资料介绍。
失效问题处理:业务分析以及资料介绍| 学习笔记
|
SQL 监控 关系型数据库
线上数据库挂了,你该如何排查?如何防备?
大家好,我是Leo,目前在常州从事Java后端工程师。上篇文章我们介绍了读写分离那些问题,主要从概念,目的,单到多的演变,安全性演变以及六个解决方案为叙述。今天我们聊聊一主多从,如果挂了你会如何快速定位。
线上数据库挂了,你该如何排查?如何防备?