news 2026/9/24 1:18:48

MySQL 5.7覆盖索引的实现方式、替代方案和限制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 5.7覆盖索引的实现方式、替代方案和限制

由于MySQL 5.7 不支持INCLUDE语法!本文我详细解释MySQL 5.7覆盖索引的实现方式、替代方案和限制:

一、MySQL的覆盖索引实现方式

MySQL 5.7的实际语法

-- MySQL 5.7 不支持INCLUDE语法-- 以下语句会报错:CREATEINDEXidx_orders_coveringONorders(customer_id,created_date)INCLUDE(amount,status,product_id);-- ❌ 语法错误!-- MySQL的正确写法:CREATEINDEXidx_orders_coveringONorders(customer_id,created_date,amount,status,product_id);-- ✅

工作原理差异

-- SQL Server/PostgreSQL:键列和包含列分离CREATEINDEXidx_separateONtable(key1,key2)INCLUDE(col3,col4);-- 索引结构:key1, key2 | col3, col4 (附加存储)-- MySQL:所有列都是键列CREATEINDEXidx_all_keysONtable(key1,key2,col3,col4);-- 索引结构:key1, key2, col3, col4 (全部参与排序)

二、MySQL 5.7的替代方案

方案1:创建复合索引(最常用)

-- 将所有需要的列都放在索引定义中CREATEINDEXidx_covering_mysqlONorders(customer_id,created_date,amount,status,product_id);-- 查询验证EXPLAINSELECTcustomer_id,created_date,amount,statusFROMordersWHEREcustomer_id=123ANDcreated_date>='2024-01-01';-- 如果Extra显示"Using index",说明使用了覆盖索引

方案2:使用索引扩展(MySQL 5.6+)

-- MySQL会自动将主键附加到二级索引末尾-- 假设主键是order_idCREATEINDEXidx_partialONorders(customer_id,created_date);-- 实际索引包含:customer_id, created_date, order_id-- 可以利用这一点SELECTcustomer_id,created_date,order_idFROMordersWHEREcustomer_id=123;-- 这个查询可以使用覆盖索引

方案3:使用生成列(MySQL 5.7+)

-- 通过生成列创建函数索引ALTERTABLEordersADDCOLUMNstatus_codeTINYINTAS(CASEstatusWHEN'pending'THEN1WHEN'shipped'THEN2WHEN'delivered'THEN3ELSE0END)STORED;-- 创建包含生成列的索引CREATEINDEXidx_with_storedONorders(customer_id,created_date,status_code);

三、MySQL覆盖索引的局限性

1.索引大小问题

-- MySQL中所有索引列都参与B+树排序-- 如果包含大字段,索引会非常庞大CREATEINDEXidx_bigONorders(customer_id,created_date,product_nameVARCHAR(200),-- 大字段会使索引很大descriptionTEXT(500)-- 更糟糕!);-- ❌ 不推荐,可能比表数据还大

2.前缀索引限制

-- 对于文本字段,可以使用前缀索引CREATEINDEXidx_text_prefixONorders(customer_id,created_date,product_name(50)-- 只索引前50个字符);-- 但可能无法完全覆盖查询SELECTcustomer_id,created_date,product_nameFROMordersWHEREcustomer_id=123;-- 如果product_name长度超过50,需要回表

3.最左前缀原则限制

-- 索引:customer_id, created_date, amount, status-- 有效查询:SELECT*FROMordersWHEREcustomer_id=123;-- ✅ 使用索引SELECT*FROMordersWHEREcustomer_id=123ANDcreated_date>'2024-01-01';-- ✅-- 无效查询:SELECT*FROMordersWHEREcreated_date>'2024-01-01';-- ❌ 不使用索引SELECT*FROMordersWHEREamount>100;-- ❌ 不使用索引

四、MySQL 5.7的优化技巧

技巧1:选择合适的列顺序

-- 按选择性和查询频率排序CREATEINDEXidx_optimizedONorders(customer_id,-- 高选择性,经常用于WHEREcreated_date,-- 范围查询,放在第二status,-- 低选择性,很少单独查询amount-- 仅用于SELECT列表);

技巧2:使用索引合并

-- 如果无法创建大型复合索引CREATEINDEXidx_customer_dateONorders(customer_id,created_date);CREATEINDEXidx_statusONorders(status);-- 查询时MySQL可能使用索引合并EXPLAINSELECTcustomer_id,created_date,amountFROMordersWHEREcustomer_id=123ANDstatus='shipped';-- 可能使用:idx_customer_date AND idx_status

技巧3:分析索引使用情况

-- 查看索引统计SELECTTABLE_NAME,INDEX_NAME,SEQ_IN_INDEX,COLUMN_NAME,CARDINALITYFROMINFORMATION_SCHEMA.STATISTICSWHERETABLE_SCHEMA='your_database'ANDTABLE_NAME='orders'ORDERBYINDEX_NAME,SEQ_IN_INDEX;-- 查看索引大小SELECTTABLE_NAME,INDEX_NAME,ROUND(INDEX_LENGTH/1024/1024,2)AS'Size(MB)'FROMINFORMATION_SCHEMA.TABLESWHERETABLE_SCHEMA='your_database'ANDTABLE_NAME='orders';

五、MySQL 8.0的改进

降序索引(MySQL 8.0+)

-- MySQL 5.7不支持降序索引,8.0支持CREATEINDEXidx_descONorders(customer_id,created_dateDESC);-- 对于ORDER BY ... DESC查询更高效

函数索引(MySQL 8.0+)

-- 直接在索引中使用函数CREATEINDEXidx_funcONorders((UPPER(customer_name)));

六、实际应用示例

场景:订单查询优化

-- 查询模式1:按客户和时间查询SELECTorder_id,customer_id,created_date,amount,statusFROMordersWHEREcustomer_id=123ANDcreated_dateBETWEEN'2024-01-01'AND'2024-01-31';-- 查询模式2:按状态和时间查询SELECTorder_id,customer_id,created_date,amountFROMordersWHEREstatus='shipped'ANDcreated_date>='2024-01-01';-- MySQL 5.7解决方案:创建两个索引CREATEINDEXidx_customer_date_coveringONorders(customer_id,created_date,amount,status);-- 注意:order_id会自动包含(主键)CREATEINDEXidx_status_date_coveringONorders(status,created_date,customer_id,amount);

七、最佳实践建议

1.避免过度索引

-- 不要为每个查询创建覆盖索引-- 评估查询频率和性能收益-- 一般原则:一个表的索引数量不超过5-7个

2.监控和维护

-- 定期分析索引使用SELECT*FROMsys.schema_unused_indexes;-- MySQL 8.0+-- 使用Performance Schema监控SELECT*FROMperformance_schema.table_io_waits_summary_by_index_usage;

3.测试验证

-- 创建索引前测试EXPLAINSELECT...-- 查看执行计划-- 创建索引后验证ANALYZETABLEorders;-- 更新统计信息EXPLAINSELECT...-- 确认索引使用
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 9:58:22

免费在线网盘解析:夸克文件高速下载

今天教大家一招能解决夸克网盘限制的在线工具。这个工具也是完全免费使用的。下面让大家看看我用这个工具的下载速度咋样。地址获取:放在这里了,可以直接获取 这个速度还是不错的把。对于平常不怎么下载的用户还是很友好的。下面开始今天的教学 输入我给…

作者头像 李华
网站建设 2026/9/24 14:12:22

Git原理与使用

✨✨ 欢迎大家来到小伞的大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Git原理与使用 小伞的主页:xiaosan_blog gitee:许星让 (xu-xingrang) - Gitee.com 制作不易!点个赞吧…

作者头像 李华
网站建设 2026/9/24 0:35:45

神经网络如何学习:一种概率视角

原文:towardsdatascience.com/how-neural-networks-learn-a-probabilistic-viewpoint-0f6a78dc58e2?sourcecollection_archive---------1-----------------------#2024-12-26 理解训练神经网络的损失函数 https://medium.com/bilalhsp?sourcepost_page---byline-…

作者头像 李华
网站建设 2026/9/24 21:28:06

PySpark实战 - 2.1 利用Spark SQL实现词频统计

文章目录1. 实战概述2. 实战步骤3. 实战总结1. 实战概述 本次实战基于 Spark SQL 对 HDFS 上的文本文件进行词频统计,通过 DataFrame API 读取数据、使用 split 与 explode 函数拆分单词,并结合临时视图与 SQL 语句完成分组计数与排序,最终将…

作者头像 李华
网站建设 2026/9/24 13:50:13

PerlinNoise Perlin噪声(PerlinNoise)隐式函数构建模型并渲染

一:主要的知识点 1、说明 本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程——逐行解析官网所有Python示例-CSDN博客 2、知识点纪要 本段代码主要涉及的有①柏林噪声的构建与渲染 二:代码…

作者头像 李华