news 2026/6/10 16:31:01

MySQL 索引真不是越多越好!聊聊索引的 “隐形代价”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 索引真不是越多越好!聊聊索引的 “隐形代价”
    • 先搞懂:索引为啥不能多?
      • 1. 写入/更新/删除速度直接变慢
      • 2. 占用大量磁盘空间
      • 3. 让MySQL优化器“选花眼”
      • 4. 浪费内存缓存
    • 哪些是“无用索引”?常见的冗余情况
      • 1. 重复索引
      • 2. 功能重复的索引
    • 怎么判断索引是否过多?实用检查方法
      • 1. 看索引数量和数据量的匹配
      • 2. 查索引使用率
      • 3. 找未使用的索引
    • 建索引的“黄金法则”:少而精才是王道
      • 1. 按业务类型决定索引数量
      • 2. 索引优先级排序(按重要性来)
      • 3. 精简索引的实战例子
      • 4. 索引管理的小技巧
    • 最后总结下

刚接触MySQL的时候,我总觉得索引建得越多越好,不管什么查询,先给字段加个索引再说。后来做项目时发现,表的写入速度越来越慢,甚至有些查询明明加了索引,却比没加还慢——这才明白,索引不是“万能钥匙”,多了反而会帮倒忙。今天就聊聊索引过多的问题,再分享些实用的建索引技巧。

先搞懂:索引为啥不能多?

索引本质是帮查询“快速定位”的数据结构,但它不是白给的,每加一个索引,都要付出对应的代价。

1. 写入/更新/删除速度直接变慢

我认为这是索引过多最明显的影响。数据写入的时候,不光要写主数据,还要给每个索引都更新一遍——就像给文件建了多个目录,新增文件时每个目录都得改,肯定费时间。

看个直观的例子,假设用户表有5个索引,执行一条插入语句:

INSERTINTOusers(name,age,city,phone,email)VALUES('张三',25,'北京','13800138000','zhangsan@example.com');

实际执行时,数据库要做6次写入操作:1次写主数据,5次更新对应的索引。

更新和删除也是同理,如果更新的字段有索引,得先删除旧的索引记录,再插入新的。我们的经验是,索引数量和写入耗时基本成正比,比如:

  • 无索引:插入1000条0.1秒
  • 1个索引:插入1000条0.2秒
  • 5个索引:插入1000条0.6秒
    多一个索引,写入压力就大一分。

2. 占用大量磁盘空间

索引本身也要存数据,而且数量多了之后,占用的空间可能比数据本身还大。我之前查过公司一个表,数据才100MB,5个索引加起来居然占了100多MB,相当于数据体积翻倍。

教大家一个查询索引占用空间的SQL,自己就能排查:

SELECTtable_name,index_name,ROUND(index_length/1024/1024,2)AS'索引大小(MB)',ROUND(data_length/1024/1024,2)AS'数据大小(MB)',ROUND(index_length/data_length,2)AS'索引/数据比'FROMinformation_schema.TABLESWHEREtable_schema='你的数据库名';

健康的情况应该是索引大小小于数据大小,如果索引比数据还大,就得考虑精简了。

3. 让MySQL优化器“选花眼”

MySQL执行查询前,优化器会先选一个最优索引。如果表有10个甚至更多索引,优化器得一个个评估哪个最合适,这个过程本身就耗CPU。

更麻烦的是,优化器可能选错索引。比如表有idx_age(age)、idx_city(city)、idx_age_city(age,city)三个索引,执行SELECT * FROM users WHERE age > 20 AND city = '北京'时,优化器可能误选idx_ageidx_city,而不是更合适的联合索引idx_age_city,导致查询变慢。

4. 浪费内存缓存

InnoDB的缓冲池是有限的,会缓存常用的数据和索引。如果索引太多,大量不常用的索引会占满缓冲池,导致真正需要的热数据没法被缓存,查询时得从磁盘读,速度自然慢。

比如缓冲池总共4GB,本来3GB缓存数据、1GB缓存常用索引,查询很快;但索引多了之后,2GB都被不常用的索引占了,数据缓存只剩2GB,频繁出现磁盘IO,性能直接下滑。

哪些是“无用索引”?常见的冗余情况

很多时候索引过多,是因为建了重复或冗余的索引,自己却没发现。

1. 重复索引

比如先建了单列索引idx_a (a),又建了联合索引idx_a_b (a,b)——idx_a就是重复索引,因为联合索引idx_a_b的前缀列是a,完全能覆盖idx_a的查询场景,留着idx_a只会增加维护成本。

2. 功能重复的索引

比如idx_a_b (a,b)idx_b_a (b,a),如果查询条件主要是a开头或b开头,可能都需要,但如果很少用b开头的查询,idx_b_a就是多余的。

还有比如idx_name (name)idx_name_part (name(20)),都是给name字段建索引,留一个合适的就行,没必要建两个。

怎么判断索引是否过多?实用检查方法

光说不行,得有具体的判断标准,分享几个我平时常用的方法。

1. 看索引数量和数据量的匹配

不同规模的表,适合的索引数量不一样:

  • 小型表(<10万行):3-5个索引足够,数据少全表扫描都快,多建索引没必要
  • 中型表(10万-1000万行):5-8个索引,平衡读写性能
  • 大型表(>1000万行):8-12个索引,再多就会严重影响写入

2. 查索引使用率

用这条SQL能看到每个索引的使用情况, rows_read很低说明索引很少被用:

SELECTobject_schemaAS数据库名,object_nameAS表名,index_nameAS索引名,rows_readAS读取次数,rows_insertedAS插入次数,rows_updatedAS更新次数,rows_deletedAS删除次数FROMperformance_schema.table_io_waits_summary_by_index_usageWHEREindex_nameISNOTNULLORDERBYrows_readDESC;

如果某个索引的rows_read是0,或者远小于rows_updated,基本就是无用索引。

3. 找未使用的索引

MySQL 8.0+有个很方便的视图,能直接查出未使用的索引:

SELECT*FROMsys.schema_unused_indexes;

低于8.0版本的话,用这条SQL手动排查:

SELECTs.index_name,s.table_name,s.rows_selected,CASEWHENs.rows_selected<1000THEN'考虑删除'WHENs.rows_selected<10000THEN'观察'ELSE'保留'ENDAS建议FROM(SELECTOBJECT_NAMEAStable_name,INDEX_NAMEASindex_name,COUNT_READASrows_selected,COUNT_UPDATEASrows_updatedFROMperformance_schema.table_io_waits_summary_by_index_usageWHEREOBJECT_SCHEMA=DATABASE())sWHERErows_selected=0OR(rows_selected<100ANDrows_updated>1000);

建索引的“黄金法则”:少而精才是王道

我认为建索引的核心是“按需创建”,不是越多越好,而是要精准。分享几个实用的策略:

1. 按业务类型决定索引数量

  • OLTP系统(比如电商交易、用户中心,频繁写入):索引要少而精,3-8个足够,只给高频查询建索引
  • OLAP系统(比如报表分析、数据仓库,频繁读取):索引可以稍多,8-15个,覆盖多种查询模式,但也要控制维护成本

2. 索引优先级排序(按重要性来)

  1. 主键索引(必须有,默认会建)
  2. 唯一约束索引(比如用户手机号、身份证号,保证数据唯一)
  3. 高频查询的WHERE条件列(比如订单表的user_id、商品表的category_id)
  4. 高频查询的JOIN条件列(比如关联查询时的外键)
  5. 高频的ORDER BY/GROUP BY列(避免排序耗时)
  6. 覆盖索引(查询的列都在索引里,不用回表,比如SELECT age,city FROM users WHERE age>25,建idx_age_city就能覆盖)
  7. 低选择性列(比如性别,选值只有男/女,建索引效果差,通常不需要)

3. 精简索引的实战例子

之前见过一个电商商品表,居然建了15个索引,包括各种单列索引和重复的联合索引,导致写入很慢。优化后精简到6个核心索引,效果立竿见影:

优化前(反面例子):

CREATETABLEproducts(idINTPRIMARYKEY,nameVARCHAR(200),category_idINT,priceDECIMAL(10,2),stockINT,statusTINYINT,created_timeDATETIME,-- 冗余索引太多INDEXidx_name(name),INDEXidx_category(category_id),INDEXidx_price(price),INDEXidx_cat_price(category_id,price),INDEXidx_cat_status(category_id,status),INDEXidx_name_part(name(20))-- 和idx_name重复);

优化后(正面例子):

CREATETABLEproducts(idINTPRIMARYKEY,nameVARCHAR(200),category_idINT,priceDECIMAL(10,2),stockINT,statusTINYINT,created_timeDATETIME,-- 6个核心索引,覆盖所有高频查询INDEXidx_cat_price_status(category_id,price,status),-- 分类+价格+状态查询INDEXidx_status_created(status,created_time),-- 状态+创建时间查询INDEXidx_name(name(50)),-- 商品名称搜索INDEXidx_stock_status(stock,status),-- 库存预警查询INDEXidx_created(created_time),-- 时间范围查询INDEXidx_cat_created(category_id,created_time)-- 分类+时间查询);

优化后写入速度提升40%,内存占用减少60%,查询性能却没下降。

4. 索引管理的小技巧

  • 定期审计:每月查一次未使用的索引,及时清理
  • 用不可见索引测试:删除索引前,先设为不可见(ALTER TABLE users ALTER INDEX idx_test INVISIBLE),观察一段时间业务无影响再删除
  • 建索引前问自己几个问题:这个查询每天执行超过100次吗?有类似索引能复用吗?表写入频繁吗?索引列选择性高吗(比如性别选择性低,不适合建)?

最后总结下

索引就像调料,放对了能提味,放多了反而毁菜。它不是越多越好,而是要在查询性能和写入成本之间找平衡。

我认为核心要点就几个:

  1. 每个索引都是“负债”,要承担维护成本,不是必需的就别建
  2. 优先建联合索引,一个设计好的联合索引能顶好几个单列索引
  3. 定期清理无用、冗余的索引,就像定期大扫除
  4. 写入频繁的表,索引一定要精简;查询频繁的表,可适当多建,但也要控制数量

其实建索引没有绝对的标准,关键是结合自己的业务场景,按需创建、定期优化。如果盲目建一堆索引,最后只会导致整个数据库性能下滑,得不偿失。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:53:11

内容审核机制:防止生成涉及盗版或侵权的信息输出

内容审核机制&#xff1a;防止生成涉及盗版或侵权的信息输出 在当前大语言模型&#xff08;LLM&#xff09;广泛应用的背景下&#xff0c;如何避免AI系统无意中成为版权内容传播的通道&#xff0c;已成为开发者和平台方必须面对的核心挑战。尤其当模型被用于教育、竞赛辅导或编…

作者头像 李华
网站建设 2026/5/18 19:43:10

【Dify触发器性能优化终极指南】:揭秘高并发场景下响应延迟的5大元凶及解决方案

第一章&#xff1a;Dify触发器性能优化的核心挑战在高并发场景下&#xff0c;Dify触发器的性能表现面临多重技术瓶颈。触发器作为连接用户请求与底层工作流的核心组件&#xff0c;其响应延迟、资源调度效率以及事件堆积处理能力直接影响系统整体可用性。事件处理延迟的根源分析…

作者头像 李华
网站建设 2026/6/10 15:36:06

网盘分类无序?VibeThinker构建智能目录树

网盘分类无序&#xff1f;VibeThinker构建智能目录树 在数字生活日益膨胀的今天&#xff0c;几乎每个人都曾面对过这样的场景&#xff1a;打开网盘&#xff0c;映入眼帘的是上百个命名混乱的文件——“新建文本文档(3).txt”、“IMG_20230412_1532.jpg”、“最终版_v2_final.do…

作者头像 李华
网站建设 2026/6/10 11:39:39

Docker镜像体积大?AI推荐精简layer策略

Docker镜像体积大&#xff1f;AI推荐精简layer策略 在AI模型日益向边缘端和本地化部署演进的今天&#xff0c;一个1.5B参数的小模型竟能在数学竞赛题上击败千亿级大模型——这听起来像天方夜谭&#xff0c;但微博开源的 VibeThinker-1.5B-APP 正在让这种“以小搏大”成为现实。…

作者头像 李华
网站建设 2026/6/10 10:40:22

三脚电感布局布线:PCB设计操作指南

从一个三脚电感说起&#xff1a;如何让电源更稳、EMI更低&#xff1f;你有没有遇到过这样的情况&#xff1f;调试一块高性能主板或显卡时&#xff0c;电源输出纹波总是压不下去&#xff0c;EMC测试频频超标&#xff0c;红外热像仪一扫&#xff0c;发现某相VRM电感烫得离谱。换更…

作者头像 李华
网站建设 2026/6/10 10:38:56

Multisim仿真下的共射极放大器深度剖析

从零搭建一个能“听见”的放大器&#xff1a;Multisim里的共射极电路实战你有没有试过把麦克风接上耳机&#xff0c;却发现什么都听不清&#xff1f;那不是设备坏了&#xff0c;而是信号太弱了——毫伏级的音频就像耳语&#xff0c;在嘈杂的电路世界里根本传不远。这时候&#…

作者头像 李华