【MySQL】第7节|Mysql锁机制与优化实践以及MVCC底层原理剖析

锁等待分析

我们通过检查InnoDB_row_lock相关的状态变量来分析系统上的行锁的争夺情况

示例场景

假设有两个用户同时操作账户表 accounts(主键为 id):

1. 用户A:执行转账,锁定账户 id=1 并等待3秒:

BEGIN;
SELECT * FROM accounts WHERE id=1 FOR UPDATE;
-- 模拟业务逻辑耗时3秒
COMMIT;

2. 用户B:几乎同时尝试锁定同一账户: 

    BEGIN;
    SELECT * FROM accounts WHERE id=1 FOR UPDATE;  -- 被阻塞,等待用户A释放锁
    COMMIT;

    参数变化说明

    1. Innodb_row_lock_current_waits
      • 含义:当前正在等待锁的事务数量。
      • 示例:当用户B被阻塞时,该值为 1;用户A提交后,该值变为 0
    2. Innodb_row_lock_waits
      • 含义:系统启动后锁等待的总次数。
      • 示例:用户B等待一次后,该值增加 1
    3. Innodb_row_lock_time
      • 含义:系统启动后所有锁等待的总时长(毫秒)。
      • 示例:用户B等待3秒(3000毫秒)后,该值增加 3000
    4. Innodb_row_lock_time_avg
      • 含义:每次锁等待的平均时长(毫秒)。
      • 示例:若此前无等待,此次等待后该值为 3000;若已有1次等待(假设为2000毫秒),则平均值为 (2000 + 3000) / 2 = 2500
    5. Innodb_row_lock_time_max
      • 含义:系统启动后最长的单次锁等待时长。
      • 示例:若此前最大值为2500毫秒,此次等待3000毫秒后,该值更新为 3000

    关键指标解读

    • 高 Innodb_row_lock_waits

    表示频繁出现锁争用,可能是事务持有锁时间过长或并发度过高。

    → 优化:缩短事务执行时间,避免长事务。

    • 高 Innodb_row_lock_time_avg

    表示锁等待时间过长,可能是锁粒度太大或索引缺失导致锁范围扩大。

    → 优化:优化查询语句,确保使用索引减少锁范围。

    • 高 Innodb_row_lock_time

    累计等待时间过长,影响整体吞吐量。

    → 优化:调整业务逻辑,减少锁竞争(如批量操作拆分为多次小事务)。

    查看方法

    SHOW STATUS LIKE 'Innodb_row_lock%';-- 输出示例:
    +-------------------------------+-------+
    | Variable_name                 | Value |
    +-------------------------------+-------+
    | Innodb_row_lock_current_waits | 0     |
    | Innodb_row_lock_time          | 3000  |
    | Innodb_row_lock_time_avg      | 3000  |
    | Innodb_row_lock_time_max      | 3000  |
    | Innodb_row_lock_waits         | 1     |
    +-------------------------------+-------+

    这些指标是 动态累积值,重启MySQL后会重置为0。通过监控它们的变化趋势,可以定位数据库性能瓶颈。

    INFORMATION_SCHEMA系统库锁相关数据表

    以下是关于 InnoDB 事务和锁相关系统表的示例说明,结合常见场景演示如何查询和分析数据:

    一、查看当前事务(INNODB_TRX / information_schema.INNODB_TRX

    场景:查询当前正在运行的事务
    SELECTtrx_id,               -- 事务IDtrx_state,            -- 事务状态(RUNNING、LOCK WAIT等)trx_started,          -- 事务开始时间trx_query,            -- 正在执行的SQL语句(可能为NULL)trx_mysql_thread_id   -- 事务对应的线程ID
    FROM INFORMATION_SCHEMA.INNODB_TRX;
    示例输出

    trx_id

    trx_state

    trx_started

    trx_query

    trx_mysql_thread_id

    12345

    LOCK WAIT

    2025-05-24 15:30:00

    SELECT * FROM accounts WHERE id=1 FOR UPDATE

    101

    12346

    RUNNING

    2025-05-24 15:29:55

    UPDATE orders SET status='paid'

    102

    说明
    • trx_state=LOCK WAIT:表示事务正在等待锁(如示例中线程101在等待锁定id=1的记录)。
    • trx_query:若事务未执行具体SQL(如处于空闲状态),则显示为NULL

    二、查看锁信息(INNODB_LOCKS → 8.0+ 改为 performance_schema.data_locks

    场景:查询当前数据库中的行锁
    -- MySQL 5.7及之前版本
    SELECTlock_id,          -- 锁IDlock_trx_id,      -- 持有锁的事务IDlock_mode,        -- 锁模式(如X锁、S锁、IS锁、IX锁)lock_table,       -- 锁定的表名lock_index,       -- 锁定的索引(若为行锁,通常为索引名)lock_space,       -- 表空间IDlock_page,        -- 数据页号lock_rec,         -- 数据行号lock_data          -- 锁定的行数据(如主键值)
    FROM INFORMATION_SCHEMA.INNODB_LOCKS;-- MySQL 8.0+ 版本(改用 performance_schema.data_locks)
    SELECTENGINE_LOCK_ID,    -- 锁IDTHREAD_ID,         -- 持有锁的线程IDLOCK_MODE,         -- 锁模式LOCK_TYPE,         -- 锁类型(ROW、TABLE等)TABLE_SCHEMA,      -- 表所属数据库TABLE_NAME,        -- 表名INDEX_NAME,        -- 索引名LOCK_DATA           -- 锁定的行数据(如主键值)
    FROM performance_schema.data_locks;
    示例输出(MySQL 8.0+)

    ENGINE_LOCK_ID

    THREAD_ID

    LOCK_MODE

    LOCK_TYPE

    TABLE_SCHEMA

    TABLE_NAME

    INDEX_NAME

    LOCK_DATA

    12345:10:4:3

    102

    X

    ROW

    test

    accounts

    PRIMARY

    1

    12346:10:4:5

    103

    S

    ROW

    test

    orders

    idx_status

    'paid'

    说明
    • LOCK_MODE=X:表示排他锁(示例中线程102对accountsid=1的记录加了X锁)。
    • LOCK_DATA:行锁通常显示主键值(如1),表锁或意向锁可能显示为NULL

    三、查看锁等待(INNODB_LOCK_WAITS → 8.0+ 改为 performance_schema.data_lock_waits

    场景:查询当前锁等待的阻塞关系
    -- MySQL 5.7及之前版本
    SELECTrequest_trx_id,     -- 请求锁的事务ID(等待者)request_lock_id,    -- 请求的锁IDblock_trx_id,       -- 持有锁的事务ID(阻塞者)block_lock_id       -- 被持有的锁ID
    FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;-- MySQL 8.0+ 版本(改用 performance_schema.data_lock_waits)
    SELECTREQUESTING_THREAD_ID,  -- 请求锁的线程ID(等待者)BLOCKING_THREAD_ID,    -- 持有锁的线程ID(阻塞者)REQUESTED_LOCK_ID,     -- 请求的锁IDBLOCKING_LOCK_ID       -- 被持有的锁ID
    FROM performance_schema.data_lock_waits;
    示例输出

    request_trx_id

    request_lock_id

    block_trx_id

    block_lock_id

    12345

    12345:10:4:3

    12346

    12346:10:4:3

    说明
    • 事务12345(等待者) 请求锁定id=1的记录,但事务12346(阻塞者) 已持有该记录的X锁,导致阻塞。
    • 通过此表可快速定位死锁或锁竞争的源头。

    四、释放锁(KILL THREAD

    场景:强制终止阻塞事务(需谨慎!)
    1. 通过 INNODB_TRX 找到阻塞事务的线程ID
    SELECT trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_id=12346;  -- 假设阻塞者事务ID为12346
    -- 输出:102
    1. 终止线程释放锁
    KILL 102;  -- 杀死线程ID为102的事务(需SUPER权限)
    注意
    • 直接终止事务可能导致数据不一致或未提交的业务逻辑中断,仅建议在紧急情况下使用(如死锁无法自动解决时)。

    五、查看锁等待详细信息(SHOW ENGINE INNODB STATUS

    场景:获取更详细的锁等待日志(包含死锁检测信息)
    SHOW ENGINE INNODB STATUS\G
    关键输出片段
    ------------------------
    LATEST DETECTED DEADLOCK
    ------------------------
    2025-05-24 15:35:00 0x7f8a12345678
    *** (1) TRANSACTION:
    TRANSACTION 12347, ACTIVE 5 sec inserting
    mysql tables in use 1, locked 1
    LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
    MySQL thread id 103, OS thread handle 12345, query id 123456 test 192.168.1.1 root
    INSERT INTO accounts (id, balance) VALUES (2, 1000)
    *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 10 page no 4 n bits 72 index PRIMARY of table `test`.`accounts` trx id 12347 lock_mode X insert intention waiting
    Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 00: len 4; hex 80000002; asc     ;;1: len 6; hex 000000003031; asc    01;;2: len 7; hex b60000019d0110; asc        ;;*** (2) TRANSACTION:
    TRANSACTION 12348, ACTIVE 6 sec inserting
    2 lock struct(s), heap size 1136, 1 row lock(s)
    MySQL thread id 104, OS thread handle 12346, query id 123457 test 192.168.1.2 root
    INSERT INTO accounts (id, balance) VALUES (1, 2000)
    *** (2) HOLDS THE LOCK(S):
    RECORD LOCKS space id 10 page no 4 n bits 72 index PRIMARY of table `test`.`accounts` trx id 12348 lock_mode X
    Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 00: len 4; hex 80000001; asc     ;;1: len 6; hex 000000003030; asc    00;;2: len 7; hex b60000019d010a; asc        ;;*** (1) AND (2) WAITING FOR EACH OTHER'S LOCKS!
    说明
    • 输出显示两个事务(12347和12348)在插入数据时发生死锁,互相等待对方持有的锁。
    • SHOW ENGINE INNODB STATUS 会打印最近一次死锁的详细信息,包括锁定的表、索引、行数据及事务操作,用于分析死锁原因。

    总结:如何通过系统表诊断锁问题

    1. 第一步:通过 INNODB_TRX 查看是否有事务处于 LOCK WAIT 状态,定位等待者和阻塞者的线程ID。
    2. 第二步:通过 data_locks 或 INNODB_LOCKS 查看具体锁的类型、锁定的表和行数据。
    3. 第三步:通过 data_lock_waits 或 INNODB_LOCK_WAITS 确认锁等待的阻塞关系。
    4. 第四步:结合 SHOW ENGINE INNODB STATUS 的详细日志分析死锁或长时间等待的原因。

    通过这些系统表的组合查询,可以快速定位数据库中的锁竞争、死锁等性能问题,并针对性优化事务逻辑或索引设计。

    死锁问题分析

    set transcation_isolation='repeatable-read';
    Session_1执行:select * from account where id=1 for update;
    Session_2执行:select * from account where id=2 for update;
    Session_1执行:select * from account where id=2 for update;
    Session_2执行:select * from account where id=1 for update;
    查看近期死锁日志信息:show engine innodb status; 

    锁优化实践

    • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
    • 合理设计索引,尽量缩小锁的范围
    • 尽可能减少检索条件范围,避免间隙锁
    • 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
    • 尽可能用低的事务隔离级别

    MVCC多版本并发控制机制

    MVCC(多版本并发控制)是MySQL中InnoDB存储引擎实现读一致性和并发控制的核心机制,主要用于读已提交(RC)和可重复读(RR)隔离级别(默认是RR)。它通过版本链一致性读视图避免锁竞争,提升并发性能。

    核心要素

    1. 版本链
      • 每行数据修改时会生成多个版本,通过隐藏字段(trx_idroll_ptr等)串联成版本链。
      • trx_id:修改数据的事务ID(唯一递增)。
      • roll_ptr:指向旧版本数据(存于回滚日志undo log)。
    2. 一致性读视图(Read View)
      • 事务执行普通查询(非锁定读,如SELECT)时,会生成一个快照(读视图),记录当前活跃事务ID列表。
      • 通过读视图判断数据版本是否可见,实现无锁读。

    在MySQL中的应用场景

    1. 不同隔离级别下的行为
    • 可重复读(RR)
      • 事务启动时生成读视图,整个事务期间只读该视图,保证多次读取结果一致(避免不可重复读和幻读)。
    -- 事务A(RR隔离级别)
    BEGIN;
    SELECT * FROM t WHERE id=1; -- 生成读视图V1,读取版本链中可见的数据
    -- 其他事务修改id=1的数据,生成新版本(trx_id=102)
    SELECT * FROM t WHERE id=1; -- 仍用V1,读取旧版本数据(不可重复读被禁止)
    COMMIT;
    • 读已提交(RC)
      • 每次查询时重新生成读视图,保证每次读取的是最新已提交数据(可能出现不可重复读)。
    -- 事务A(RC隔离级别)
    BEGIN;
    SELECT * FROM t WHERE id=1; -- 读视图V1,读取旧版本
    -- 其他事务提交修改(trx_id=102)
    SELECT * FROM t WHERE id=1; -- 重新生成V2,读取新版本(允许不可重复读)
    COMMIT;
    2. 与锁的配合
    • 快照读(非阻塞读):普通SELECT使用MVCC,不加锁,读旧版本数据(一致性读)。
    • 当前读(阻塞读):加锁语句(如SELECT ... FOR UPDATE)直接读最新数据,需等待锁释放。
    -- 事务A(当前读)
    SELECT * FROM t WHERE id=1 FOR UPDATE; -- 读取最新数据,加行锁,阻塞其他写事务
    3. 提升并发性能
    • 写操作(如INSERT/UPDATE/DELETE)生成新版本,读操作通过MVCC访问旧版本,避免读写阻塞。
    • 场景:高并发读场景(如电商商品详情页),读不阻塞写,写不阻塞读。

    关键特性

    • 无锁读:普通查询不阻塞写事务,反之亦然(除了SERIALIZABLE隔离级别)。
    • 读一致性:根据隔离级别控制数据可见性,避免脏读、不可重复读等问题。
    • 回滚日志管理:旧版本数据存于undo log,由InnoDB自动清理(purge线程),避免日志膨胀。

    总结

    MVCC是InnoDB实现高并发的基石,通过版本链和读视图在一致性并发性间找到平衡。理解其原理有助于优化事务设计(如合理选择隔离级别)和排查锁问题(如长时间锁等待可能因MVCC版本链过长导致)。

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82061.shtml

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    基于规则引擎与机器学习的智能Web应用防火墙设计与实现

    基于规则引擎与机器学习的智能Web应用防火墙设计与实现 引言:智能防御的必然选择 在2023年OWASP最新报告中,传统Web应用防火墙(WAF)对新型API攻击的漏报率高达67%,而误报导致的正常业务拦截损失每年超过2.3亿美元。面…

    GIM发布新版本了 (附rust CLI制作brew bottle流程)

    GIM 发布新版本了!现在1.3.0版本可用了 可以通过brew upgrade git-intelligence-message升级。 初次安装需要先执行 brew tap davelet/gim GIM 是一个根据git仓库内文件变更自动生成git提交消息的命令行工具,参考前文《GIM: 根据代码变更自动生成git提交…

    PyQt5高效布局指南:QTabWidget与QStackedWidget实战解析

    🔍 问题背景 当界面控件过多时,直接平铺会导致窗口拥挤、用户体验下降。PyQt5提供了两种高效容器控件: QTabWidget:选项卡式布局,支持直接切换不同功能模块QStackedWidget:堆栈式布局,需配合导…

    《2.2.1顺序表的定义|精讲篇》

    上一节学习了线性表的逻辑结构,线性表需要实现哪些基本运算/操作?在本节中,我们将学习顺序表的定义、顺序表的特性,以及如何用代码来实现顺序表。下个小节我们会介绍基于顺序存储(这种存储结构)如何用代码具…

    【 大模型技术驱动智能网联汽车革命:关键技术解析与未来趋势】

    大模型技术驱动智能网联汽车革命:关键技术解析与未来趋势 关键词总结: 大模型技术:LLM、VLM、MLLM、Transformer架构核心场景:智能驾驶、智能座舱、智能网联关键技术:端到端系统、BEVOCC网络、多模态融合、强化学习挑…

    Rocketmq broker 是主从架构还是集群架构,可以故障自动转移吗

    RocketMQ Broker的架构与故障转移机制 RocketMQ的Broker架构同时采用了主从架构和集群架构,并且支持故障自动转移。下面详细说明: 一、架构类型 1. 集群架构 RocketMQ天然支持分布式集群部署 一个RocketMQ集群包含多个Broker组(每组有主从) 不同Bro…

    从零开始建立个人品牌并验证定位变现性的方法论——基于开源AI大模型、AI智能名片与S2B2C商城生态的实证研究

    摘要:本文提出一种融合开源AI大模型、AI智能名片与S2B2C商城小程序源码的"最小测试闭环"方法论,通过技术赋能实现个人品牌定位的精准验证与变现路径优化。以某美妆领域自由职业者为例,其通过开源AI大模型完成能力图谱构建与资源匹配…

    SQL进阶之旅 Day 2:高效的表设计与规范:从基础到实战

    【SQL进阶之旅 Day 2】高效的表设计与规范:从基础到实战 开篇 在数据库开发中,一个良好的表设计不仅能够提高查询效率,还能避免冗余数据和一致性问题。本文作为"SQL进阶之旅"系列的第2天,将重点介绍高效的表设计与规范…

    Java—— IO流的应用

    带权重的点名系统 案例要求 文件中有学生的信息,每个学生的信息独占一行。包括学生的姓名,性别,权重 要求每次被抽中的学生,再次被抽中的概率在原先的基础上降低一半。 本题的核心就是带权重的随机 分析 权重,权重和…

    Docker中部署Alertmanager

    在 Docker 中部署 Alertmanager(通常与 Prometheus 告警系统配合使用)的步骤如下: 一、拉取镜像prom/alertmanager docker pull prom/alertmanager二、 创建 Alertmanager 配置文件 首先准备Alertmanager的配置文件 alertmanager.yml(如存…

    【大模型面试每日一题】Day 27:自注意力机制中Q/K/V矩阵的作用与缩放因子原理

    【大模型面试每日一题】Day 27:自注意力机制中Q/K/V矩阵的作用与缩放因子原理 📌 题目重现 🌟🌟 面试官:请解释Transformer自注意力机制中Query、Key、Value矩阵的核心作用,并分析为何在计算注意力分数时…

    AI+能碳管理系统:全生命周期碳管理

    在"双碳"目标的时代背景下,AI赋能的能碳管理系统正在重新定义企业碳管理的边界与深度。这套系统犹如一位不知疲倦的碳管家,从原材料采购到产品报废,在每一个价值环节编织起精密的碳管理网络,实现从微观设备到宏观战略的…

    k8s1.27版本集群部署minio分布式

    需求: 1.创建4个pv,一个pv一个minio-pod。使用sts动态分配pvc(根据存储类找到pv)。----持久化 2.暴露minio的9001端口。(nodeport)----管理界面 镜像:minio/minio:RELEASE.2023-03-20T20-16-18Z--->换国内源 说明…

    使用 OpenCV 实现 ArUco 码识别与坐标轴绘制

    🎯 使用 OpenCV 实现 ArUco 码识别与坐标轴绘制(含Python源码) Aruco 是一种广泛用于机器人、增强现实(AR)和相机标定的方形标记系统。本文将带你一步一步使用 Python OpenCV 实现图像中多个 ArUco 码的检测与坐标轴…

    Qt 控件发展历程 + 目标(1)

    文章目录 声明简述控件的发展历程学习目标QWidget属性 简介:这篇文章只是一个引子,介绍一点与控件相关的但不重要的内容(浏览浏览即可),这一章节最为重要的还是要把之后常用且重要的控件属性和作用给学透,学…

    socc 19 echash论文部分解读

    前言:论文还是得吃透才行,不然很多细节有问题 q1 object和data chunck哪一个大 根据论文,一个 data chunk 通常比一个 object 大,因为它是由多个 object 组合而成的 。 论文中提到,cross-coding 会将多个 object 组合…

    w~自动驾驶~合集1

    我自己的原文哦~ https://blog.51cto.com/whaosoft/12371169 #世界模型和DriveGPT这类大模型到底能给自动驾驶带来什么ne 以下分享大模型与自动驾驶结合的相关工作9篇论 1、ADAPT ADAPT: Action-aware Driving Caption Transformer(ICRA2023) A…

    【paddle】常见的数学运算

    根据提供的 PaddlePaddle 函数列表,我们可以将它们按照数学运算、逻辑运算、三角函数、特殊函数、统计函数、张量操作和其他操作等类型进行分类。以下是根据函数功能进行的分类: 取整运算 Rounding functions 代码描述round(x)距离 x 最近的整数floor(…

    绘制音频信号的各种频谱图,包括Mel频谱图、STFT频谱图等。它不仅能够绘制频谱图librosa.display.specshow

    librosa.display.specshow 是一个非常方便的函数,用于绘制音频信号的各种频谱图,包括Mel频谱图、STFT频谱图等。它不仅能够绘制频谱图,还能自动设置轴标签和刻度,使得生成的图像更加直观和易于理解。 ### 函数签名 python libros…

    DDR DFI 5.2 协议接口学习梳理笔记01

    备注:本文新增对各种时钟含义做了明确定义区分,避免大家产生误解,这也是5.2版本新引入的。 1. 前言 截止2025年5月,DFI协议最新版本为 5.2,我们首先看一下过去几代的演进: DFI全称DDR PHY Interface,是一种接口协议,定义了 Controller 和 PHY 之间接口的信号、时序以…