SQL 大表加索引为什么危险?

10次阅读

大表加索引危险在于同时冲击锁、性能、空间和稳定性四大维度:旧版mysql全程锁表,新版仍可能触发MDL锁;建索引耗尽CPU与I/O,加剧主从延迟;磁盘占用翻倍易致失败;索引还可能因函数、类型转换或顺序错配而失效。

SQL 大表加索引为什么危险?

大表加索引之所以危险,核心在于它会同时冲击数据库锁、性能、空间和稳定性四大关键维度,稍有不慎就可能引发线上故障。

锁表导致业务写入中断

MySQL 5.6 及更早版本中,ALTER table ... ADD INDEX 采用 copy 算法,全程对表加写锁,期间所有 INSERT/UPdate/delete 都会被阻塞。即使在 MySQL 5.7+ 支持 Online DDL,某些操作(如全文索引、主键变更)仍可能触发短暂但致命的元数据锁(MDL),尤其在高并发写场景下,容易积大量等待线程

CPU 和 I/O 资源被彻底打满

创建索引需全表扫描并排序建树,过程消耗巨大:

  • 单线程建索引时,CPU 利用率常飙至 90%+,拖慢其他查询响应
  • 磁盘随机读 + 大量顺序写(索引页、redo log、binlog),I/O wait 暴涨
  • 主从复制延迟可能激增——binlog 写入滞后,从库追不上主库节奏

磁盘空间突然告急

索引不是“轻量附加”,而是实实在在的额外存储:

  • 普通二级索引体积约为原表数据的 20%–50%,千万级表轻松多占数 GB
  • 建索引过程中,InnoDB 会先写临时索引文件,再原子替换,高峰期磁盘占用可达 原表 + 新索引 × 2
  • 若空间不足,操作失败且回滚耗时极长(可能数十分钟),期间资源持续被占用

索引建了一半却失效或误用

即便成功加完索引,也不代表能用上:

  • WHERE 条件对索引列用了函数(如 WHERE DATE(create_time) = '2025-01-01')、隐式类型转换phone = 13800138000,而 phone 是 VARCHAR)都会让索引失效
  • 联合索引顺序不匹配(如建了 (a,b,c) 却只查 WHERE b = ?),前面字段未参与,后面全作废
  • 低选择性字段(如 status、gender)单独建索引,查询优化器大概率弃用,纯属浪费

不复杂但容易忽略:危险从来不是“能不能加”,而是“加得是否可控、可退、可验证”。

text=ZqhQzanResources