阿里技术 02月01日
MySQL索引学习笔记
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了MySQL数据库中慢查询分析的关键概念和技术手段。文章从响应时间、扫描行数和返回行数三个维度分析了查询开销,并通过案例展示了索引对查询性能的影响。重点介绍了三星索引评价体系,聚簇索引的存储方式及其优缺点,覆盖索引的优势,以及索引列顺序和最左前缀法则。此外,还详细阐述了排序操作的索引优化策略,强调了避免文件排序的重要性,并提供了多个示例来解释索引在排序中的应用。

⏱️ 响应时间是衡量查询开销的关键指标,包括服务时间和排队时间。服务时间是数据库处理查询的实际耗时,排队时间是等待资源的时间,如I/O或行锁。

⭐ 三星索引评价体系用于判断索引是否适合查询,一星代表索引将相关记录放在一起,二星代表索引顺序与查找顺序一致,三星代表索引包含查询所需全部列。

🗂️ 聚簇索引是一种数据存储方式,数据行和键值紧凑存储,InnoDB根据主键聚簇数据。聚簇索引的优点是数据访问快,缺点是插入顺序依赖性高,更新代价高,可能导致页分裂。

✅ 覆盖索引是指索引包含了查询所需的所有字段,避免了回表查询,可以极大地提高性能,特别是在InnoDB表中,二级索引覆盖查询可以避免对主键索引的二次查询。

🔀 索引列顺序的选择应考虑列的选择性,选择性高的列放在前面,最左前缀法则要求查询条件需从索引最左边开始,不能跳过索引中的列,排序操作应尽量利用索引,避免文件排序。

功路 2025-02-01 08:30 浙江

本文深入探讨了MySQL数据库中慢查询分析的关键概念和技术手段。



这是2025年的第11篇文章

( 本文阅读时间:15分钟 )



01



慢查询分析

对于MySQL,最简单的衡量查询开销的三个指标如下:


1.1 分析示例

我们看一下示例数据库Sakila中的一个查询案例:

select * from film_actor where film_id = 1 -- film_id列有索引


这个查询将返回10行数据,从EXPLAIN的结果可以看到,MySQL在索引idx_fk_film_id上使用了ref访问类型来执行查询:









EXPLAIN的结果还显示MySQL预估需要访问10行数据。换句话说,查询优化器认为这种访问类型可以高效地完成查询。


如果没有合适的索引会怎样呢?MySQL就不得不使用一种糟糕的访问类型,下面来看看如果删除对应的索引再来运行这个查询会发生什么情况:





访问类型变成了一个全表扫描(ALL),现在MySQL预估需要扫描5462条记录来完成这个查询。这里的“Using where”表示MySQL将通过WHERE条件来筛选存储引擎返回的记录。


一般地,MySQL能够使用如下三种方式应用WHERE条件,从好到坏依次为:



02



三星索引

“三星系统”(three-star system)评价体系,用以判断一个索引是不是适合某个查询语句:



03



聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式,术语“聚簇”表示数据行和相邻的键值紧凑地存储在一起。InnoDB的聚簇索引实际上保存了B-tree索引和数据行(聚簇索引的每一个叶子节点都包含了主键值、事务ID、用于事务和MVCC的回滚指针,以及所有的剩余列)。当表有聚簇索引时,它的数据行实际上存放在索引的叶子页(leaf page)中。一个表只能有一个聚簇索引,叶子页包含了一条记录的全部数据。 


InnoDB根据主键聚簇数据。如果你没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。聚集的数据有一些重要的优点:



同时,聚簇索引也有一些缺点:




04



覆盖索引

如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为覆盖索引。覆盖索引是非常有用的工具,能够极大地提高性能。试想一下,如果查询只需要扫描索引而无须回表,会带来多少好处:




05



索引列顺序(怎么指定索引列顺序)

不需要考虑排序和分组时,将选择性最高的列放在前面通常是很好的。这时索引的作用只是优化查询语句中的WHERE条件。在这种情况下,按这个原则设计的索引确实能够最快地过滤出需要的行。以下面的查询为例:

select * from payment where staff_id = 123 and customer_id = 456


是应该创建一个(staff_id、customer_id)索引还是应该颠倒一下顺序?这时,可以通过运行某些查询来确定在这个表中值的分布情况,并确定哪列的选择性更高。先用下面的查询预测一下,看看各个WHERE条件的分支对应的数据基数有多大:





根据前面的经验法则,应该将索引列customer_id放到前面,因为对应条件值的customer_id数量更小。

5.1 索引最左前缀法则‌

指在MySQL中使用索引时,查询条件需要从索引的最左边开始,并且不能跳过索引中的列。如果查询条件跳过了索引中的某列,那么索引将失效,后续的列也不会被使用。‌

select * from payment where staff_id = 123 -- 索引是customer_id,staff_id,因为漏掉了customer_id,所以走不上索引

5.2 排序是否命中索引

无论如何排序都是一个成本很高的操作,所以从性能角度考虑,应尽可能避免排序或者尽可能避免对大量数据进行排序。当不能使用索引生成排序结果的时候,MySQL需要自己进行排序,如果数据量小则在内存中进行,如果数据量大则需要使用磁盘,不过MySQL将这个过程统一称为文件排序(filesort),即使完全是在内存中排序不需要任何磁盘文件时也是如此。


只有当索引的顺序和ORDER BY子句的顺序完全一致,并且所有列的排序方向(倒序或正序)都一样时,MySQL才能使用索引来对结果做排序。如果查询需要联接多张表,则只有当ORDER BY子句引用的字段全部在第一个表中时,才能使用索引做排序。ORDER BY子句和查找型查询的限制是一样的:需要满足索引的最左前缀的要求,否则,MySQL需要执行排序操作,而无法利用索引排序。


有一种特殊情况,如果前导列为常量的时候,ORDER BY子句中的列也可以不满足索引的最左前缀的要求。如果在WHERE子句或者JOIN子句中将这些列指定为了常量,就可以“填补”索引字段的间隙了。


例如,Sakila示例数据库的表rental在列(rental_date,inventory_id,customer_id)上建有名称为rental_date的索引:





不需要文件排序

MySQL可以使用rental_date索引为下面的查询做排序,从EXPLAIN中可以看到没有出现文件排序(filesort)操作:




select * from rental where rental_date = '2005-05-25' order by inventory_id, customer_id -- rental_date是常量,后面的排序列则认为符合最左前缀

select * from rental where rental_date = '2005-05-25' order by inventory_id, customer_id,id -- rental_date是常量,后面的排序列则认为符合最左前缀,虽然索引里面没有显示指定id列,id是隐性的包含在索引中的,所以也无需文件排序


即使ORDER BY子句不满足索引的最左前缀的要求,也可以用于查询排序,这正是因为索引的第一列被指定为了一个常数。


需要文件排序

select * from rental where rental_date > '2005-05-25' order by rental_date, inventory_id -- 符合最左前缀


下面是一些不能使用索引做排序的查询:

select * from rental where rental_date = '2005-05-25' order by inventory_id asc,  customer_id desc -- 满足最左前缀,但是排序方向不一样


select * from rental where rental_date = '2005-05-25' order by inventory_id ,staff_id -- staff_id不在索引中


select * from rental where rental_date = '2005-05-25' order by customer_id -- 不满足最左前缀,漏掉了inventory_id


select * from rental where rental_date > '2005-05-25' order by  inventory_id -- 第一列如果是范围查询,则认为不符合最左前缀


select * from rental where rental_date = '2005-05-25' and inventory_id in (1,2) order by customer_id -- inventory_id 条件是范围查询,则认为不符合最左前缀




欢迎留言一起参与讨论~



阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

MySQL 慢查询分析 索引优化 聚簇索引 覆盖索引
相关文章