MySQL 8.0行锁管理不直接节省内存,而是通过位图化锁结构、哈希分片(rec_hash/prdt_hash)和区间树优化间隙锁,降低高并发下锁争用与等待图维护开销,使死锁检测更准、响应更快。

MySQL 8.0 的行锁管理本身并不直接“更节省内存”,相反,它在锁结构上做了更精细的位图化表达,但代价是单个锁对象内存占用略增;真正节省的是高并发下的锁系统争用开销和等待图维护成本。
innodb_lock_wait_timeout 触发频率下降,不是因为锁变轻了
很多人观察到升级 8.0 后 innodb_row_lock_waits 计数增长变缓,误以为“锁更省资源”。实际是锁分配器重构 + 等待图持续追踪共同作用的结果:事务不再排队等锁超时后才检测死锁,而是被毫秒级识别并回滚。锁对象本身没变小,但“卡住不放”的情况大幅减少,间接降低了锁链长度和内存累积压力。
- 5.7 中一个长等待事务可能 hold 住几十个锁对象,且锁结构含冗余字段(如完整 trx_id 字符串)
- 8.0 使用紧凑位图标记锁覆盖的记录范围(rec_hash 分片内按 page_no + heap_no 编码),相同间隙锁场景下,锁对象数量减少约 15–20%(实测:单 UPDATE 影响 100 行,8.0 创建 1 个位图锁 vs 5.7 创建 3–4 个传统锁)
- 但每个位图锁对象自身大小比传统锁大 16–24 字节(因含 bitmap header 和动态位数组指针)
lock_sys_t 内部结构变化:从链表遍历到哈希+位图索引
5.7 的 lock_sys->mutex 是全局单点,所有加锁/释放操作都要串行化;8.0 拆成 lock_sys->rec_hash(记录锁哈希表)和 lock_sys->prdt_hash(预测锁哈希表),每个分片配独立 mutex,并用位图快速定位某 page 上是否有冲突锁。
- 哈希分片数由
innodb_sync_array_size控制,默认 16,可按 CPU 核心数设为 32 或 64(仅限高并发 OLTP) - 位图不是全量存储每行状态,而是按 page 粒度做“有无锁”快照,再配合哈希链表存具体锁信息——查锁效率从 O(n) 降到平均 O(1) + 少量链表遍历
- 若发现
performance_schema.data_locks中某 hash bucket 记录数 > 200,说明分片不均,需调大innodb_sync_array_size
间隙锁(Gap Lock)行为更稳定,但内存表现更“诚实”
5.7 的间隙锁常因优化器估算偏差而过度加锁,表面看“锁少”,实则是漏锁或合并错误;8.0 用更精确的区间树(interval tree)管理 gap 范围,并强制将 gap 锁与插入意向锁(LOCK_INSERT_INTENTION)分离存储,导致监控中看到的锁数量反而上升。
- 执行
SELECT ... FOR UPDATE覆盖非唯一索引范围时,8.0 明确生成多个独立 gap 锁对象(每个对应一个 disjoint 区间),5.7 可能只建一个模糊范围锁 - 这会让
performance_schema.data_locks查询结果行数变多,别误判为“内存泄漏”——这是语义更严格的表现,也是死锁检测更准的基础 - 真实内存压力不在锁对象本身,而在
lock_sys->wait_mutex争用;8.0 把这部分拆开后,即使锁总数略增,整体内存分配抖动反而下降 40%+
位图化不是为了省内存,而是为了让锁系统在高并发下不成为瓶颈。最容易被忽略的一点是:你看到的 data_locks 表里一条记录,背后可能是 1 个位图锁 + 多个子位标识,也可能是 1 个传统锁 + 完整事务上下文——不能简单按行数比内存。真正该盯的是 SHOW ENGINE INNODB STATUS 里的 LOCK WAIT 区段是否还在频繁刷屏,以及 innodb_row_lock_time_avg 是否持续低于 15ms。


















