0

0

MySQL联合索引与覆盖索引实战_Sublime语句示例分析索引命中情况

雪夜

雪夜

发布时间:2025-07-31 16:55:02

|

288人浏览过

|

来源于php中文网

原创

要判断mysql查询是否使用了联合索引或覆盖索引,需使用explain命令分析查询计划;1.查看type列:ref、range、eq_ref表示有效使用索引;2.查看key列:显示实际使用的索引名称;3.查看key_len列:反映索引的哪部分被使用;4.查看extra列:using index表示覆盖索引生效。联合索引的列顺序影响查询性能,遵循最左前缀原则;1.索引列顺序应优先放置区分度高且常用于等值匹配的列;2.范围查询后的列无法有效利用索引;3.设计时需结合具体查询模式以最大化索引利用率。

MySQL联合索引与覆盖索引实战_Sublime语句示例分析索引命中情况

当谈到MySQL性能优化,联合索引和覆盖索引绝对是绕不开的话题。简单来说,联合索引就是多个列组合在一起创建的索引,而覆盖索引则是一种特殊情况,它意味着查询所需的所有数据都可以在索引本身中找到,无需回表查询数据行。这两种索引策略,如果用得好,能让你的数据库查询速度飞起来,尤其是在处理大量数据时,那效果简直立竿见影。我个人在实际项目中,经常会遇到一些慢查询,追根溯源,往往就是索引没用对或者压根没索引。所以,理解并实战这俩概念,真不是什么理论知识,而是提升系统响应速度的硬核技能。

MySQL联合索引与覆盖索引实战_Sublime语句示例分析索引命中情况

实战联合索引和覆盖索引,我的经验是,得从你的查询语句出发,反推索引设计。假设我们有一个orders表,包含user_id, order_status, order_time, amount等字段。

场景一:联合索引优化多条件查询 我们经常会查询某个用户在特定状态下的订单,比如:

MySQL联合索引与覆盖索引实战_Sublime语句示例分析索引命中情况
SELECT * FROM orders WHERE user_id = 123 AND order_status = 'completed' ORDER BY order_time DESC;

对于这个查询,一个常见的错误是只给user_idorder_status单独建索引。但更优的做法是创建一个联合索引:(user_id, order_status, order_time)

在Sublime Text里,我通常会这样写SQL,然后用EXPLAIN分析:

MySQL联合索引与覆盖索引实战_Sublime语句示例分析索引命中情况
-- 创建联合索引
CREATE INDEX idx_user_status_time ON orders (user_id, order_status, order_time);

-- 查询语句
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND order_status = 'completed' ORDER BY order_time DESC;

执行EXPLAIN后,关注typekeykey_lenrefextra这些列。如果typerefrange,并且key显示使用了idx_user_status_time,那就说明联合索引被有效利用了。key_len会告诉你索引的哪部分被用到了,这对于理解索引的最左前缀原则非常关键。

场景二:覆盖索引避免回表 现在,假设我们只需要查询满足条件的用户ID和订单时间,不需要其他字段:

SELECT user_id, order_time FROM orders WHERE user_id = 123 AND order_status = 'completed';

如果我们的联合索引是(user_id, order_status, order_time),那么这个查询就是一个典型的覆盖索引案例。因为SELECT列表中的user_idorder_time,以及WHERE条件中的user_idorder_status,所有需要的数据都可以在这个索引的B+树节点中直接获取,数据库引擎无需再去访问实际的数据行(回表)。

在Sublime里,我同样会用EXPLAIN来验证:

EXPLAIN SELECT user_id, order_time FROM orders WHERE user_id = 123 AND order_status = 'completed';

这次,EXPLAINExtra列会显示Using index。这个提示就是覆盖索引生效的标志。它意味着查询完全依赖索引,没有进行回表操作,性能自然是极高的。

我遇到过不少开发者,他们在查询SELECT *的时候,即便有联合索引,也无法实现覆盖索引的效果,因为*意味着需要所有列的数据,而索引通常只包含部分列。所以,精细化你的SELECT列表,只选取你真正需要的字段,是实现覆盖索引,进一步提升性能的关键一步。当然,这在某些ORM框架下可能没那么直观,但理解这个原理,能帮助你更好地优化ORM生成的SQL。

HTTPie AI
HTTPie AI

AI API开发工具

下载

如何判断MySQL查询是否使用了联合索引或覆盖索引?

判断MySQL查询是否有效使用了索引,特别是联合索引和覆盖索引,最直接也是最权威的工具就是EXPLAIN命令。这是我日常工作中分析慢查询的起手式。

当你执行EXPLAIN your_sql_query;后,会得到一张结果表,你需要重点关注以下几个字段:

  • type: 这是最重要的指标之一,它表示MySQL如何查找表中的行。
    • const, eq_ref, ref: 这些是最高效的类型,表示通过索引进行精确查找。ref通常是联合索引的最左前缀匹配或单个索引的等值匹配。
    • range: 表示索引范围扫描,比如WHERE id BETWEEN 10 AND 20
    • index: 表示全索引扫描,虽然比全表扫描(ALL)好,但如果索引很大,性能可能依然不理想。它通常发生在覆盖索引生效,但WHERE条件无法利用索引进行过滤时。
    • ALL: 最差的类型,表示全表扫描,意味着没有使用索引,或者索引选择性太差被优化器放弃。
  • key: 明确指出MySQL实际使用的索引名称。如果这里显示了你创建的联合索引名称,那么它肯定被用到了。如果显示NULL,那显然没用上索引。
  • key_len: 显示MySQL实际使用的索引的长度(字节数)。这个值可以帮助你理解联合索引的最左前缀原则。如果你的联合索引是(a, b, c),当你只用a查询时,key_len会显示a的长度;如果用a, b查询,则显示ab的长度之和。这能直观地告诉你索引的哪部分被利用了。
  • rows: 估计MySQL为了找到所需行而需要读取的行数。这个值越小越好。
  • Extra: 这是判断覆盖索引的关键。
    • Using index: 这是覆盖索引的明确标志。它表示查询所需的所有数据都可以在索引中找到,无需回表查询数据行。
    • Using where: 表示MySQL需要通过WHERE子句来过滤结果。如果同时出现Using index,通常是好的;如果单独出现,可能意味着索引没有完全满足查询条件,或者需要额外的过滤步骤。
    • Using filesort: 表示MySQL需要对结果进行外部排序,通常发生在ORDER BY子句中的列没有被索引覆盖,或者索引顺序与排序顺序不匹配时。这通常是性能瓶颈。
    • Using temporary: 表示MySQL需要创建临时表来处理查询,通常发生在复杂的GROUP BYDISTINCT操作中,也是性能隐患。

我通常会把EXPLAIN的结果复制到Sublime Text里,然后逐行分析,特别是typeExtra。如果type不是ALL,并且ExtraUsing index,那这个查询的索引优化基本就到位了。如果出现Using filesortUsing temporary,我就会开始思考如何调整索引或SQL语句来避免它们。

联合索引的列顺序对查询性能有何影响?

联合索引的列顺序,简直是索引设计中的“玄学”,但实际上它有非常明确的逻辑,那就是“最左前缀原则”。这个原则决定了你的联合索引能否被有效利用,以及在何种程度上被利用。

简单来说,如果你的联合索引是(col1, col2, col3),那么它可以支持以下几种查询模式:

  1. 只使用col1:WHERE col1 = 'xxx'
  2. 使用col1col2:WHERE col1 = 'xxx' AND col2 = 'yyy'
  3. 使用col1col2col3:WHERE col1 = 'xxx' AND col2 = 'yyy' AND col3 = 'zzz'
  4. 使用col1col3,但col2是范围查询或不存在:WHERE col1 = 'xxx' AND col3 = 'zzz' (此时col3可能无法完全利用索引,因为它跳过了col2)

但它不能直接支持:

  • 只使用col2:WHERE col2 = 'yyy'
  • 只使用col3:WHERE col3 = 'zzz'
  • 使用col2col3:WHERE col2 = 'yyy' AND col3 = 'zzz'

这就意味着,在设计联合索引时,你需要把查询中最常用作等值匹配(=IN)的列放在前面,尤其是那些选择性(Cardinality,即不重复值的数量)高的列。

举个例子,如果你的orders表经常有这样的查询: SELECT * FROM orders WHERE user_id = ? AND order_status = ?;SELECT * FROM orders WHERE user_id = ?;SELECT * FROM orders WHERE order_status = ?;

那么,将user_id放在联合索引的第一位,即(user_id, order_status),会比(order_status, user_id)更优。因为user_id通常选择性更高(用户ID一般不重复),而且它能满足user_id单独查询的需求。而order_status通常只有少数几个值(比如'completed', 'pending', 'cancelled'),选择性很低。如果把order_status放在第一位,那么对于user_id的查询就无法利用索引,对于order_status的查询,即便利用了索引,也可能因为选择性太低而扫描大量数据。

一个实用的经验是:将区分度高的列放在联合索引的前面,然后是区分度一般的,最后是区分度低的。同时,也要考虑你的查询模式。如果某个列经常用于范围查询(>, , BETWEEN),那么它之后的列可能就无法有效利用索引了。例如,索引(a, b, c),如果查询是WHERE a = 1 AND b > 10 AND c = 5,那么c将无法利用索引,因为b

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

674

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

319

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

345

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1084

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

355

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

672

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

566

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

409

2024.04.29

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

3

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.5万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 777人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号