数码港
霓虹主题四 · 更硬核的阅读氛围

创建索引会影响性能吗 使用技巧与常见问题解析

发布时间:2026-01-13 03:20:31 阅读:216 次

数据库用久了,查询变慢是常有的事。很多人第一反应就是加个索引, hoping 能让查询飞起来。但你有没有遇到过,建完索引后,系统反而更卡了?这时候就得琢磨一句:创建索引,真的不会影响性能吗?

索引不是免费的午餐

很多人以为索引就像书后面的目录,查起来快,还不占地方。但实际上,每建一个索引,数据库都得额外维护一份数据结构。比如你在 user 表的 email 字段上建了个索引,那每次插入一条新用户,数据库不仅要写数据行,还得把这个 email 值塞进索引树里。

这就好比你开了家小店,本来记账本就一本,客人一多,翻起来费劲。于是你搞了个按姓名排序的索引本。查人是快了,但每来一个新客户,你得同时往两个本子上写,工作量自然就上去了。

写操作变慢是常态

尤其是高频写入的场景,比如日志表、订单流水,频繁插入、更新、删除。如果这些表上索引太多,每个写操作都得同步更新多个索引,CPU 和 I/O 压力立马就上来了。有时候你会发现,某个接口突然变慢,查了半天发现是后台在批量导入数据,而表上有七八个索引,每个都要重建维护。

举个真实例子:有个朋友在一张每天新增百万条记录的日志表上,给五个字段都加了单独索引。结果插入速度从每秒 5000 条掉到不到 1000 条。最后只能删掉冗余索引,只保留最常用的复合索引,才缓过来。

索引也会占用内存和磁盘

索引文件本身要占磁盘空间,而且数据库通常会把热索引加载到内存里加速访问。如果索引太大,可能挤占原本用来缓存数据的内存,导致缓存命中率下降。MySQL 的 InnoDB 引擎就有这种情况,buffer pool 被索引占满,数据页反而老被刷出去。

什么时候建索引影响小?

查询远多于写入的表,比如配置表、用户信息表,建索引收益明显。这类表一天可能就几十次写操作,但被查上千次,加个索引能省下大量全表扫描的开销。

另外,合理使用复合索引也能减少数量。比如经常按 status 和 create_time 查询,与其分别建两个单列索引,不如建一个 (status, create_time) 的联合索引,既能覆盖查询,又避免维护多个树结构。

CREATE INDEX idx_status_time ON orders (status, create_time);

别盲目建索引,先看执行计划

建索引前,用 EXPLAIN 看看 SQL 到底走不走索引。有时候你以为需要,其实优化器压根不用。还有的时候,索引建了,但因为函数包裹、隐式类型转换,照样失效。

EXPLAIN SELECT * FROM users WHERE YEAR(create_time) = 2024;

这条 SQL 即使 create_time 有索引,也可能用不上,因为套了 YEAR() 函数。正确的做法是改写成范围查询。

定期检查冗余索引

项目迭代多了,有些索引可能没人用了。比如某个功能下线,但对应的索引还在。可以用 performance_schema 或者 pt-index-usage 工具分析哪些索引长期未被使用,及时清理。

还有一个常见问题:重复索引。比如主键 id 上已经有了索引,你还单独建一个单列索引 on (id),纯属多余。还有像 (a,b) 和 (a) 这种,后者通常是冗余的,除非你有只查 a 的特定场景。

所以,建索引不是一劳永逸的事。它是一把双刃剑,用好了风驰电掣,用不好反而拖垮系统。关键是在查询效率和写入成本之间找平衡,别让“提速”的初衷,变成了新的瓶颈。