信息发布→ 登录 注册 退出

mysql中的索引与事务处理性能的关联

发布时间:2026-01-13

点击量:
索引会拖慢事务写入速度,因每次DML需同步更新所有相关索引,导致写放大、B+树分裂、唯一性校验开销及锁竞争加剧。

索引会拖慢事务的写入速度

事务中涉及 INSERTUPDATEDELETE 操作时,每修改一行数据,MySQL 都要同步更新所有相关索引。索引越多,写放大越严重——不是只改 1 行数据,而是可能触发 B+ 树分裂、页合并、二级索引回表更新等额外开销。

  • 单个 UPDATE 语句若命中 1000 行,且该表有 5 个二级索引,实际磁盘写入量可能接近原始数据的 6 倍(主键 + 5 个索引)
  • UNIQUE 索引在写入前必须做唯一性校验,会引发额外的索引查找,尤其在高并发下容易成为锁竞争热点
  • 使用 bulk insert 时,先 DROP INDEX 再重建,常比逐条插入快 3–10 倍(需权衡维护窗口)

事务隔离级别影响索引扫描范围和锁粒度

不同隔离级别下,MySQL 对索引的访问方式和加锁行为差异极大。比如 REPEATABLE READ 下的 SELECT ... FOR UPDATE 不仅锁住匹配行,还可能锁住索引间隙(Gap Lock),而 READ COMMITTED 默认只锁行(Record Lock),不锁间隙。

  • WHERE status = ? 上建了索引,但 status 值分布极不均匀(如 95% 是 'pending'),会导致大范围索引扫描 + 大量行锁,事务容易被阻塞
  • SELECT * FROM t WHERE id > 1000 ORDER BY id LIMIT 1id 主键上有索引,但若事务中先执行了未提交的 DELETE FROM t WHERE id = 1001,在 REPEATABLE READ 下可能触发间隙锁,把 (1000, 1001) 区间也锁住
  • EXPLAIN FORMAT=tree 查看执行计划时,注意 access_type 是否为 rangeindex;如果是全索引扫描(type: index),即使走了索引,也可能因锁太多导致事务吞吐骤降

长事务让索引统计信息过期,优化器选错执行计划

MySQL 的索引基数(cardinality)统计依赖采样,且不会在事务运行中动态刷新。一个持续数分钟的事务,期间大量 DML 修改数据分布,但优化器仍按旧统计估算成本,可能放弃本该走的索引,转而用全表扫描。

  • 现象:某 SELECT 在事务内第一次执行很快(走了索引),第二次变慢(type: ALL),SHOW INDEX FROM t 显示 Cardinality 值明显滞后于实际
  • 临时缓解:手动执行 ANALYZE TABLE t,但会加 MDL 锁,生产环境慎用;更稳妥的是避免长事务,把大事务拆成小批次(例如每次处理 1000 行)
  • 监控线索:观察 information_schema.INNODB_TRXTRX_STARTED 时间戳,结合 performance_schema.events_statements_current 定位长时间未提交的查询

唯一索引冲突直接导致事务回滚或死锁

当两个并发事务尝试插入相同 UNIQUE KEY 值时,MySQL 必须在索引层面检测冲突。这个过程涉及对索引记录加 S 锁(共享锁)再升级为 X 锁(排他锁),极易与其它事务形成循环等待。

  • 典型死锁日志里会出现类似 lock_mode X locks gap before rec insert intention waiting,说明两个事务都在等对方释放唯一索引的间隙锁
  • 应用层不要依赖 INSERT IGNOREON DUPLICATE KEY UPDATE 来“兜底”唯一冲突,它们只是掩盖问题;应提前用 SELECT ... FOR UPDATE 加锁检查,或改用分布式 ID + 应用层幂等控制
  • 如果业务允许,把 UNIQUE 约束从数据库下推到应用层缓存(如 Redis SETNX),可显著降低索引锁争用
SELECT 
  trx_id,
  trx_state,
  trx_started,
  trx_weight,
  trx_mysql_thread_id
FROM information_schema.INNODB_TRX 
WHERE trx_state = 'RUNNING' AND TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;

索引不是越全越好,事务不是越长越稳。真正卡住性能的,往往是那条没走索引的 SELECT 拿着锁不放,或是那个被忽略的 UNIQUE 索引在高并发下成了锁瓶颈。

标签:# 并发  # 太多  # 成了  # 同步更新  # 主键  # 的是  # 加锁  # 应用层  # 锁住  # 走了  # 死锁  # 数据库  # table  # mysql  # delete  # 循环  # format  # select  # for  # 分布式  # red  # 热点  # ai  # access  # redis  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!