mysql并发下索引会影响性能吗_mysql索引与并发关系

来源:这里教程网 时间:2026-02-28 20:43:03 作者:

并发写入时二级索引会显著拖慢性能

是的,MySQL 在高并发写入场景下,二级索引(非主键索引)会成为明显瓶颈。InnoDB 的聚簇索引结构决定了每条

INSERT
UPDATE
涉及二级索引时,都要额外维护 B+ 树结构——包括页分裂、锁竞争、缓冲池压力等。尤其当多个事务同时向同一索引页插入数据(如按时间戳递增的
created_at
字段建索引),极易触发
LOCK_REC_NOT_GAP
行锁争用,甚至升级为间隙锁冲突。

单表写入 QPS 超过 2000 后,若存在 3 个以上二级索引,
innodb_row_lock_waits
innodb_row_lock_time_avg
监控值通常明显上升
INSERT ... ON DUPLICATE KEY UPDATE
对二级索引列做
UNIQUE
约束检查时,会先加
SELECT ... FOR UPDATE
类似锁,放大等待时间
使用
LOAD DATA INFILE
批量导入时,建议先
DROP INDEX
,导入完成再重建,避免逐行索引更新

唯一索引 vs 普通索引在并发更新中的锁行为差异

唯一索引(

UNIQUE
)和普通索引(
INDEX
)在并发
UPDATE
INSERT
时,锁粒度与加锁时机完全不同。InnoDB 对唯一索引可以“精确查找 + 精确加锁”,而普通索引必须走范围扫描,常导致更宽的锁范围。

对唯一索引列执行
UPDATE t SET x=1 WHERE uid=123
:只锁匹配的那条记录(假设
uid
UNIQUE
对普通索引列执行相同语句(如
status
非唯一):可能锁住整个索引区间,甚至触发
next-key lock
,阻塞相邻值的插入
INSERT INTO t (a,b) VALUES (1,2)
,若
(a,b)
是唯一联合索引,则只检查并锁住该组合;若仅为普通索引,则需扫描索引范围确认重复性,开销更大

高并发读场景下索引反而能缓解锁冲突

读多写少且使用

SELECT ... LOCK IN SHARE MODE
SELECT ... FOR UPDATE
的场景中,合适的索引反而降低锁粒度,减少事务间干扰。没有索引时,InnoDB 只能走聚簇索引全表扫描,整张表都可能被锁住。

缺少索引的
SELECT * FROM orders WHERE user_id = 12345 FOR UPDATE
:可能锁住成百上千行,甚至整个聚簇索引页
user_id
加了索引后:只锁住匹配的几行记录及其间隙,其他用户订单操作基本不受影响
注意:覆盖索引(
index covering
)可避免回表,在
SELECT
中只查索引字段时,连聚簇索引都不用访问,进一步减少锁和 I/O

如何验证当前索引是否正在引发并发瓶颈

别猜,直接看 InnoDB 的实时状态和慢日志。重点盯三个指标:锁等待、索引变更频率、缓冲池效率。

查锁等待:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 2;
结合
INNODB_LOCK_WAITS
查谁在等谁
看索引写入开销:
SHOW ENGINE INNODB STATUS\G
关注
ROW OPERATIONS
下的
inserts
/
updates
index inserts
比值,若后者远高于前者,说明二级索引维护成本过高
检查慢日志里是否高频出现
Creating sort index
Copying to tmp table
:这类操作常因缺失索引被迫排序或临时表,加剧并发资源争抢

索引不是越多越好,也不是越少越安全。真正麻烦的是那些“看起来有用、实际很少被查询命中、却在每次写入时强制更新”的二级索引——它们安静地躺在

SHOW CREATE TABLE
里,却在并发高峰时悄悄拖垮整个表。

相关推荐