当前位置: 首页 > news >正文

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...-- 确认索引使用
http://www.cnnetsun.cn/news/168250.html

相关文章:

  • 免费在线网盘解析:夸克文件高速下载
  • Git原理与使用
  • 神经网络如何学习:一种概率视角
  • 亲测10款降ai率工具:AI率80%怎么一键降低ai?(2025最新降AIGC避坑指南)
  • PySpark实战 - 2.1 利用Spark SQL实现词频统计
  • PerlinNoise Perlin噪声(PerlinNoise)隐式函数构建模型并渲染
  • Linly-Talker支持模型性能 profiling,精准定位瓶颈
  • Linly-Talker如何处理中英文混读?语音识别适配策略
  • LLM 的思考方式
  • 【虚拟同步机控制建模】三相虚拟同步发电机双环控制(Simulink仿真实现)
  • 万字长文!关于AI绘图,一篇超详细的总结发布
  • 数字人会议主持:Linly-Talker在远程会议中的创新应用
  • 【顶级EI完整复现】【DRCC】考虑N-1准则的分布鲁棒机会约束低碳经济调度(Matlab代码实现)
  • 用Linly-Talker做企业宣传片?品牌传播的AI新路径
  • Electerm(桌面终端模拟软件)
  • Thinkphp和Laravel基于Vue的黄山旅游景区门票预订网站的设计与实现_3h38caai
  • Thinkphp和Laravel基于大数据架构的大学生求职招聘就业岗位推荐系统的设计与实现_67911t4j
  • AI工具实战测评技术
  • 创意AI应用开发大赛技术
  • 全球股市估值与海洋微生物能源技术的关系
  • 基于python的同城宠物照看数据可视化分析系统的设计与实现_34cl0po8--论文
  • 【路径规划】基于RRT快速探索随机树的图像地图路径规划实现3附matlab代码
  • Quartz 工作模式,是“堵塞排队”还是“并发狂奔”?
  • 【FFNN负荷预测】基于人工神经网络的空压机负荷预测(Matlab代码实现)
  • 【C2000系列DSP的反向灌电流】为什么热插拔的时候I2C总线电平会被拉低?
  • Gemini Inc靶场练习(包含suid提权,文件包含漏洞,ssh免密登录)
  • 软件解耦与扩展:插件式开发方式(基于 C++ 与 C# 的实现)
  • 免费降AI率的工具红黑榜:认准这2个免费降AI率工具,亲测有效!
  • 霍华德·马克斯的市场周期定位技巧
  • 1500字免费降AIGC率的额度,2026年毕业论文查重必备!