踩坑 MySQL 索引,看看你真的会用吗?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 关于 MySQL 索引,对于研发同学,尤其是后端研发同学,一定不会陌生。我们工作中经常会用到 MySQL 数据库,就肯定会经常用到性能优化方面的设计和考量,常常用涉及到 MySQL 索引。但是关于 MySQL 索引,你真的用对了么?

关于 MySQL 索引,对于研发同学,尤其是后端研发同学,一定不会陌生。我们工作中经常会用到 MySQL 数据库,就肯定会经常用到性能优化方面的设计和考量,常常用涉及到 MySQL 索引。但是关于 MySQL 索引,你真的用对了么?


对了,在开始正式知识点讲解之前,还需要来个不那么正式的自我介绍吧,哈哈哈~


我多年后端研发经验,“混迹”于多个互联网大厂,专注软件架构技术研究学习,希望能够持续发挥自身多余的热量,将自己工作中的问题和技术总结输出,分享影响到更多的人。


大家看我的头像图片像是一个陀螺,其实是寓意螺旋式上升,让技术和自我能够不断精进。


微信图片_20220608212055.jpg


接下来,我会通过一个自己工作中真实遇到一个 MySQL 查询应用问题为背景,来逐步剖析分析,见招拆招,以科学理论为依据,分析探究,希望能带大家一起明确索引应用原则,最终将问题探究清楚。


主要原则:问题驱动;


主要流程:应用现象-问题分析-疑点跟进-层层探究-结论明晰。


那接下来,让我们利用约 15min 的时间,让自由的思路飞一会儿吧!


问题介绍


我们存在这样一张数据表(cities),记录了城市 code 和名称一些基本数据。


微信图片_20220608212058.png


有一天,我在执行如下 SQL 的时候(一个是指定了字段 id,另一个未指定查询字段,而是利用了 *),发现两种情况下查询执行结果竟然不一样!


Case1:select id from cities limit 1;


查询结果:

id:2


Case2:select * from cities limit 1;


查询结果:


微信图片_20220608212101.png


这事成功的引起了我的注意,那就继续搞起吧!


问题分析


按照之前的工作经验告诉我,遇事不要慌,先 explain 解释执行看看吧。


Case1:explain select id from cities limit 1;


执行结果:


微信图片_20220608212104.png


Case2:explain select * from cities limit 1;


执行结果:


微信图片_20220608212106.png


经过上面的执行计划查看,发现 Case1 中的 SQL 应用到了一个名为'uniq_city_code'的索引,而第二个走了全表扫描查询。


问题初步结论:也就是说两个 SQL 由于查询字段的不同,导致 MySQL 在具体执行时候选取了不同的索引策略,从而导致了查询结果的不同。


疑点跟进


其实经过上面的分析,其实还存在几个疑问点:


  • 为什么 Case1 查询中并没有出现 city_code 字段,却会使用其索引?


  • 为什么 Case2 查询就不会使用 uniq_city_code 的索引?


可能细心的同学也发现了,还有就是 Case2 查询计划中 Extra 字段为 Using index,说明满足了索引覆盖(索引中包含了所有满足查询条件的数据,无需从表中查询),可是 uniq_city_code 这个索引中并没有 id 这个字段,为何能以覆盖索引的方式执行?


带着上面的一脸疑问,我们先来一起回顾下 MySQL 引擎索引的实现方式吧。

如图所示,为 Innodb、以及参考对比的 MyISAM 引擎的索引实现图例。


1、InnoDB 聚簇索引和辅助索引(非聚簇索引)的对比图示


微信图片_20220608212110.png

同时便于大家理解,我标记黄线、红线分别代表两种引擎方式的数据查询路径,大家可以参照图例,体会对比一下。


InnoDB 按聚簇索引的形式存储数据,所以它的数据布局有着很大的不同。


1)聚簇索引中的每个叶子节点包含 primary key 的值,事务 ID 和回滚指针(rollback pointer)——用于事务和 MVCC,和余下的列(如 col2)。


2)相对于 MyISAM,辅助索引与聚簇索引有很大的不同。InnoDB 的二级索引的叶子包含 primary key 的值,而不是行指针(row pointers),这减小了移动数据或者数据页面分裂时维护二级索引的开销,因为 InnoDB 不需要更新索引的行指针。


2、MyISAM 引擎方式索引图示


微信图片_20220608212113.png


MyISAM 不支持聚簇索引,索引中每一个叶子节点仅仅包含行号(row number),且叶子节点按照 col1 的顺序存储。


在 MyISAM 中,primary key 和其它索引没有什么区别。Primary key 仅仅只是一个叫做 PRIMARY 的唯一,非空的索引而已。


好了,我们还是回到问题本身。


我们其实可以得出这样一个初步结论:


Case1:select id from cities limit 1;


因为 uniq_city_code 索引中包含 id 字段,此查询可以从 uniq_city_code 索引中直接取得数据,所以优化器选择走 uniq_city_code 索引;


Case2:select * from cities limit 1;


此查询中 select * 选取了在 uniq_city_code 索引中不包含的列,所以无法使用 uniq_city_code 这个索引。


为了验证一下我们刚刚得到的初步结论,我们来利用 Case3 验证一下。


Case3:select id, city_code from cities limit 1;


执行结果:

微信图片_20220608212115.png


按照上述的理论依据,Case1(查询 id)与 Case3(查询 id+city_code)执行应用的查询计划应该是一致的。


通过验证实验我们可以确定一个结论:Case1 的查询确实存在索引覆盖情况。


官方辅证


我们再继续追问一下:为什么要用到索引覆盖呢?不用可不可以呢?

我们先来看看 MySQL 官方的解释...

微信图片_20220608212118.png


其实说了这么多,本质就是最后一句,这样做可以使查询更快!


好了,大家可以一起来思考下这个问题:


既然主键索引包含所有数据列,那么使用主键索引一样可以做到索引覆盖,为什么优化器不选择使用主键索引?”


......


其实这个问题,就是典型的 MySQL 索引选取原则。


MySQL 在做全表扫描时,MySQL 会调用 find_shortest_key() 来选取最短的索引来扫描。


关于 find_shortest_key()函数的解释,我们来看下官方解释,如下所示:


微信图片_20220608212121.png

所以,上面大家一起思考的这个问题,答案就是:索引长度不同,有多个可选索引时,MYSQL 会优先选择较短的索引。


到现在,那我们可以对整个问题做个总结了:因为辅助索引一定是主键索引的子集,从节约 IO 的角度,在全表扫描时优先选择辅助索引。


总结


好了,最后我们一起来对整个分享做下总结吧。


1)首先我们遇到一个查询问题,由于查询字段的不同导致我们的查询结果数据存在差异;


2)我们对问题进行追究,发现根据 select 的字段不同,MySQL 选取的索引策略不同,即结果数据不同;


3)对于是否存在索引覆盖问题,我们进行了 Case3 的验证,确认了存在索引覆盖的问题;


4)对于 MySQL 为什么会存在这样的索引选取原则,我们最终发现是辅助索引一定是主键索引的子集,从节约 IO 的角度,在全表扫描时优先选择辅助索引。


重点提炼:


不同引擎对于查询实现方式的不同、索引覆盖、MySQL 索引选取原则。


不同引擎对于查询实现方式的不同、索引覆盖、MySQL 索引选取原则。


不同引擎对于查询实现方式的不同、索引覆盖、MySQL 索引选取原则。


重要的问题说三遍,哈哈哈~


其实踩坑,也是一种成长!


其实面对任何问题,都不要一上来就急于给出结论,可以尝试多做些深入分析,了解本质问题之后再考虑解决办法进行解决,希望大家能够掌握问题分析以及解决的能力,去触类旁通,而不是仅仅了解一招一式,盲目照搬。


微信图片_20220608212124.jpg

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6天前
|
缓存 关系型数据库 MySQL
MySQL索引策略与查询性能调优实战
在实际应用中,需要根据具体的业务需求和查询模式,综合运用索引策略和查询性能调优方法,不断地测试和优化,以提高MySQL数据库的查询性能。
|
29天前
|
存储 关系型数据库 MySQL
阿里面试:为什么要索引?什么是MySQL索引?底层结构是什么?
尼恩是一位资深架构师,他在自己的读者交流群中分享了关于MySQL索引的重要知识点。索引是帮助MySQL高效获取数据的数据结构,主要作用包括显著提升查询速度、降低磁盘I/O次数、优化排序与分组操作以及提升复杂查询的性能。MySQL支持多种索引类型,如主键索引、唯一索引、普通索引、全文索引和空间数据索引。索引的底层数据结构主要是B+树,它能够有效支持范围查询和顺序遍历,同时保持高效的插入、删除和查找性能。尼恩还强调了索引的优缺点,并提供了多个面试题及其解答,帮助读者在面试中脱颖而出。相关资料可在公众号【技术自由圈】获取。
|
1月前
|
存储 NoSQL 关系型数据库
为什么MySQL不使用红黑树做索引
本文详细探讨了MySQL索引机制,解释了为何添加索引能提升查询效率。索引如同数据库的“目录”,在数据量庞大时提高查询速度。文中介绍了常见索引数据结构:哈希表、有序数组和搜索树(包括二叉树、平衡二叉树、红黑树、B-树和B+树)。重点分析了B+树在MyISAM和InnoDB引擎中的应用,并讨论了聚簇索引、非聚簇索引、联合索引及最左前缀原则。最后,还介绍了LSM-Tree在高频写入场景下的优势。通过对比多种数据结构,帮助理解不同场景下的索引选择。
78 6
|
1月前
|
SQL 关系型数据库 MySQL
案例剖析:MySQL唯一索引并发插入导致死锁!
案例剖析:MySQL唯一索引并发插入导致死锁!
106 0
案例剖析:MySQL唯一索引并发插入导致死锁!
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
63 3
Mysql(4)—数据库索引
|
20天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
95 1
|
30天前
|
存储 关系型数据库 MySQL
如何在MySQL中进行索引的创建和管理?
【10月更文挑战第16天】如何在MySQL中进行索引的创建和管理?
63 1
|
21天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
49 0
|
1月前
|
监控 关系型数据库 MySQL
MySQL数据表索引命名规范
MySQL数据表索引命名规范
60 1
|
1月前
|
存储 SQL 关系型数据库
mysql中主键索引和联合索引的原理与区别
本文详细介绍了MySQL中的主键索引和联合索引原理及其区别。主键索引按主键值排序,叶节点仅存储数据区,而索引页则存储索引和指向数据域的指针。联合索引由多个字段组成,遵循最左前缀原则,可提高查询效率。文章还探讨了索引扫描原理、索引失效情况及设计原则,并对比了InnoDB与MyISAM存储引擎中聚簇索引和非聚簇索引的特点。对于优化MySQL性能具有参考价值。
下一篇
无影云桌面