当前位置:首页 > 问答 > 正文

树叶云数据库里教你怎么改删MySQL索引,DROP INDEX那点事儿讲清楚

基于MySQL官方文档8.0版本中关于DROP INDEX的说明,并结合常见的数据库管理实践和社区经验分享)

“树叶云数据库里教你怎么改删MySQL索引,DROP INDEX那点事儿讲清楚”

咱们今天就来专门聊聊在MySQL里删除索引这个操作,也就是用DROP INDEX这个命令,你别看它只是一个简单的命令,里面的门道和需要注意的地方可不少,搞不好就会惹出麻烦,咱们得把它彻底讲清楚。

最核心的问题就是:我们为什么要删除一个索引?索引不是用来加快查询速度的吗?没错,索引就像是书本的目录,能让我们快速找到想要的内容,这个“目录”并不是免费的,它是有代价的。

第一个代价是占用空间,每个索引都需要额外的磁盘空间来存储,如果你的数据量非常大,比如有几亿条记录,那么多建几个索引可能就会占用相当可观的存储空间。

第二个代价,也是更重要的代价,是会影响数据写入的速度,当你往表里插入一条新数据,或者更新、删除一条现有数据时,MySQL不仅需要改动表本身的数据,还需要更新所有相关的索引来保持“目录”的准确性,想象一下,你在一本很厚的书里每增加一页,就要同时更新几十个不同的目录,这肯定会减慢你写字的速度,数据库也是同理,索引越多,写入操作(INSERT, UPDATE, DELETE)就会越慢。

在以下这些情况下,你就需要考虑删除某个索引了:

  1. 这个索引根本没用上:你可能之前为了某个查询创建了索引,但后来业务逻辑变了,那个查询不再执行了,或者MySQL的查询优化器经过判断,认为走全表扫描比用你这个索引更快(比如在数据量很小,或者表里某个值重复率非常高的字段上建索引),这个索引就成了一个纯粹的负担,白白占用空间和拖慢写入速度,你可以通过查询INFORMATION_SCHEMA数据库里的统计信息或者使用SHOW INDEX命令来观察索引的使用情况。
  2. 有重复或冗余的索引:这是非常常见的一种情况,你已经在字段(A, B)上建立了一个联合索引,那么单独在字段(A)上再建一个索引基本上就是多余的,因为联合索引(A, B)本身就可以用来加速只查询A字段的条件,这个单独的(A)索引就是冗余索引,应该被删除,再比如,你在同一个字段上创建了多个相同类型的索引,这也是没必要的,MySQL只会用一个。
  3. 索引设计不合理:比如早期设计时考虑不周,建的索引选择性很差(即这个字段的值大部分都相同,性别”字段),这种索引对查询提速效果微乎其微,反而带来写入开销。

好了,知道了为什么要删,接下来就是怎么删了。DROP INDEX的基本语法非常简单:

DROP INDEX index_name ON table_name;

这里index_name就是你要删除的索引的名字,table_name是索引所在的表的名字。

在你兴高采烈地执行这个命令之前,有极其重要的几点必须注意:

第一点,也是最重要的一点:DROP INDEX是一个DDL操作,它会锁表!

树叶云数据库里教你怎么改删MySQL索引,DROP INDEX那点事儿讲清楚

这是什么意思呢?DDL指的是数据定义语言,像创建、修改、删除表、索引这些操作都属于DDL,当你执行DROP INDEX时,MySQL为了确保数据的一致性,通常需要对整个表加上一个排他锁(exclusive lock),在这个锁生效期间,这个表上的其他所有操作(包括读和写)都会被阻塞住,直到索引删除完成。

如果你的表非常大,删除索引的过程可能会花费几秒、几十秒甚至更长时间,在这段时间里,你的应用程序所有对这个表的访问都会卡住,就像交通堵塞一样,这很可能导致线上服务超时、报错,造成故障。

绝对不要在业务高峰期执行DROP INDEX操作!一定要选择在业务低峰期,比如深夜或者流量最小的时候进行,并且提前通知相关人员。

第二点,你不能删除主键索引(PRIMARY KEY)和唯一约束(UNIQUE CONSTRAINT)吗?

这里有个细节,在MySQL中,主键索引本身也是索引,但它附带了“非空且唯一”的约束,如果你尝试用DROP INDEX PRIMARY KEY ON table_name;来删除主键,MySQL会报错,因为一张表不能没有主键(虽然语法上允许,但强烈不推荐),要删除主键,你需要使用ALTER TABLE语句:ALTER TABLE table_name DROP PRIMARY KEY;

同样,对于唯一约束,它背后其实也是一个唯一索引,但你删除它时,更规范的写法也是使用ALTER TABLEALTER TABLE table_name DROP INDEX unique_index_name;,你直接用DROP INDEX也能删掉,但为了清晰起见,建议区分开。

树叶云数据库里教你怎么改删MySQL索引,DROP INDEX那点事儿讲清楚

第三点,删除前一定要确认索引名和表名。

这是最基本的操作安全,在运行删除命令前,最好先用SHOW INDEX FROM table_name;命令查看一下这个表到底有哪些索引,确认好你要删的那个索引的名字准确无误,输错了索引名,命令会执行失败;但万一你输错了表名,那可能就删到别的表上去了,后果更严重,在生产环境操作前,最好在测试环境先演练一遍。

第四点,考虑是否有更好的替代方案?

与其直接删除一个索引,或许有更优化的办法,这个索引虽然对当前的主要查询没用,但对一些偶尔运行的报表查询很有帮助,你或许可以权衡一下,是否值得保留它,或者,是不是可以优化一下查询语句本身,让它能利用上其他更高效的索引,从而让这个低效的索引变得可删。

删除索引DROP INDEX是一个强大的工具,用得好可以给数据库“减负”,提升写入性能,但它也是一把双刃剑,鲁莽使用会导致线上服务中断,记住几个关键原则:删前评估(是否真的没用)、选对时机(低峰期)、确认对象(索引名表名无误)、了解后果(会锁表)

希望这点事儿能给你讲清楚,让你在管理MySQL索引时心里更有底。