news 2026/4/22 12:07:57

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/4/17 21:19:32

AI法律顾问助手:帮助用户理解复杂合同条款

AI法律顾问助手:让合同条款“活”起来 想象一下,你刚拿到一份长达二十页的租房合同,满眼都是“不可抗力”“违约责任”“排他性条款”……头大如斗。如果这时,屏幕上走出一位穿着得体、语气沉稳的“律师”,一边指着关键…

作者头像 李华
网站建设 2026/4/22 18:16:24

RotationAroundLine 模型的旋转

一:主要的知识点 1、说明 本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程——逐行解析官网所有Python示例-CSDN博客 2、知识点纪要 本段代码主要涉及的有①模型的旋转 二:代码及注释 i…

作者头像 李华
网站建设 2026/4/18 13:58:42

AI 编码时代的生产力跃迁:2025 年开发者生态报告深度解读

大家好,我是Tony Bai。“如果你觉得今年的 PR (Pull Request) 变大了,你的感觉是对的。如果你觉得代码写得更快了,这也是对的。事实上,整个软件开发的节奏,正在被 AI 全面重塑。”近日,Greptile 发布了《20…

作者头像 李华
网站建设 2026/4/18 10:32:50

Linly-Talker支持模型热切换,A/B测试轻松实现

Linly-Talker支持模型热切换,A/B测试轻松实现 在虚拟主播直播间里,观众正在提问:“这款产品的优惠力度能再大点吗?” 数字人主播几乎立刻回应:“目前已经是限时五折,前100名下单还送专属礼品哦!…

作者头像 李华
网站建设 2026/4/18 1:58:02

如何利用 LLM 推动基因编辑革命

原文:towardsdatascience.com/how-llms-can-fuel-gene-editing-revolution-1b15663f697c |人工智能| 长语言模型| 基因编辑| 医学中的 AI| https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0cf407a93a483ec598632eb4690812fb.p…

作者头像 李华