当前位置: 首页 > news >正文

MVCC(多版本并发控制):InnoDB 高并发的核心技术

🔄 MVCC(多版本并发控制):InnoDB 高并发的核心技术

文章目录

  • 🔄 MVCC(多版本并发控制):InnoDB 高并发的核心技术
  • 🧠 一、MVCC 核心概念
    • ⚡ 并发控制的挑战
    • 🎯 MVCC 基本思想
  • 📖 二、快照读与当前读
    • 🔍 两种读取方式
    • 📊 操作对比分析
  • 🔗 三、Undo Log 与版本链
    • 📝 Undo Log 的作用
    • 🔗 版本链机制
    • 🛠️ 版本链访问示例
  • ⚖️ 四、隔离级别下的 MVCC
    • 🔄 Read View 机制
    • 📊 RC vs RR 隔离级别
    • 🎯 幻读解决方案
  • 💡 五、总结与最佳实践
    • 🏆 MVCC 优势总结
    • 🛠️ 最佳实践建议
    • ⚠️ 注意事项
    • 🔮 进阶技巧

🧠 一、MVCC 核心概念

⚡ 并发控制的挑战

​​传统锁机制的局限性​​

  • 读写冲突严重

  • 并发性能瓶颈

  • 死锁风险增加

​​​​MVCC 的解决方案​​​​

写操作
创建新版本
旧版本保留
读操作
选择可见版本
非阻塞读取

🎯 MVCC 基本思想

​​多版本并发控制核心原理​​​​

  • 每个写操作创建数据新版本

  • 读操作选择适当的历史版本

  • 读写操作互不阻塞

​​​​优势对比​​​​:

特性锁机制MVCC
读写冲突严重
并发性能较低
一致性强一致性快照一致性
实现复杂度简单复杂

📖 二、快照读与当前读

🔍 两种读取方式

​​1. 快照读(Snapshot Read)​

-- 普通 SELECT 查询(快照读)
SELECT * FROM products WHERE id = 1;
-- 读取历史版本,不加锁,非阻塞

​​2. 当前读(Current Read)​​

-- 当前读操作
SELECT * FROM products WHERE id = 1 FOR UPDATE; -- 加锁
UPDATE products SET price = 899 WHERE id = 1;    -- 加锁
DELETE FROM products WHERE id = 1;               -- 加锁
INSERT INTO products VALUES (1, 'Laptop', 999); -- 加锁

📊 操作对比分析

-- 会话A:更新操作
START TRANSACTION;
UPDATE products SET price = 899 WHERE id = 1;-- 会话B:不同的读取方式
START TRANSACTION;-- 快照读:看到更新前的数据(旧版本)
SELECT * FROM products WHERE id = 1; -- price = 999-- 当前读:看到最新数据(等待锁释放)
SELECT * FROM products WHERE id = 1 FOR UPDATE; -- 等待...

🔗 三、Undo Log 与版本链

📝 Undo Log 的作用

​​Undo Log 的三大功能​​​​:

  1. ​​事务回滚​​​​:记录旧值用于回滚
  2. ​​MVCC 支持​​​​:存储历史版本数据
  3. ​​崩溃恢复​​​​:保证数据一致性

​​​​Undo Log 存储结构​​​​:

-- 查看 Undo Log 配置
SHOW VARIABLES LIKE 'innodb_undo%';
/*
innodb_undo_directory = ./undo      -- 存储路径
innodb_undo_tablespaces = 2         -- Tablespace数量
innodb_undo_logs = 128              -- 回滚段数量
*/

🔗 版本链机制

​​隐藏字段​​:

数据行
DB_ROW_ID: 行ID
DB_TRX_ID: 事务ID
DB_ROLL_PTR: 回滚指针

​​版本链形成过程​​​​:

版本v4
版本v3
版本v2
版本v1
TRX_ID:104
PRICE:899
TRX_ID:103
PRICE:850
TRX_ID:102
PRICE:799
TRX_ID:101
PRICE:999

🛠️ 版本链访问示例

​​数据演变过程​​:

-- 初始状态
INSERT INTO products VALUES (1, 'Laptop', 999);
-- TRX_ID=101, ROLL_PTR=null-- 第一次更新
UPDATE products SET price = 799 WHERE id = 1;
-- TRX_ID=102, ROLL_PTR→v1-- 第二次更新
UPDATE products SET price = 850 WHERE id = 1;
-- TRX_ID=103, ROLL_PTR→v2-- 第三次更新
UPDATE products SET price = 899 WHERE id = 1;
-- TRX_ID=104, ROLL_PTR→v3

​​版本链遍历​​:

-- 当前事务TRX_ID=105,查询数据
SELECT * FROM products WHERE id = 1;
-- 从v4开始遍历版本链
-- 根据事务可见性规则选择合适版本

⚖️ 四、隔离级别下的 MVCC

🔄 Read View 机制

​​Read View 关键组件​​:

Read View
trx_ids: 活跃事务列表
low_limit_id: 最小活跃ID
up_limit_id: 最大活跃ID
creator_trx_id: 创建者ID

可见性判断算法​​:

  1. TRX_ID < low_limit_id:可见
  2. TRX_ID >= up_limit_id:不可见
  3. TRX_ID 在 trx_ids 中:不可见
  4. 其他情况:可见

📊 RC vs RR 隔离级别

​​READ COMMITTED​​

-- 每次查询创建新Read View
START TRANSACTION;
SELECT * FROM products WHERE id = 1; -- 创建Read View1
-- 其他事务提交修改
SELECT * FROM products WHERE id = 1; -- 创建Read View2,看到新提交

​​REPEATABLE READ​​

-- 第一次查询创建Read View并复用
START TRANSACTION;
SELECT * FROM products WHERE id = 1; -- 创建Read View
-- 其他事务提交修改
SELECT * FROM products WHERE id = 1; -- 复用同一个Read View,看不到新提交

🎯 幻读解决方案

​​​​MVCC 限制​​​​:

  • MVCC 解决了快照读的幻读

  • 当前读仍需 Next-Key Lock 防止幻读

​​​​示例演示​​​​

-- 会话A:REPEATABLE READ
START TRANSACTION;
SELECT * FROM products WHERE price > 800; -- 快照读,返回1条-- 会话B:插入新记录并提交
INSERT INTO products VALUES (2, 'Tablet', 899);
COMMIT;-- 会话A:再次查询(仍然返回1条,无幻读)
SELECT * FROM products WHERE price > 800; -- 快照读-- 但是当前读可能产生幻读
SELECT * FROM products WHERE price > 800 FOR UPDATE; -- 需要Next-Key Lock

💡 五、总结与最佳实践

🏆 MVCC 优势总结

​​核心价值​​

  • ✅ 读写不阻塞,提升并发性能

  • ✅ 避免脏读,保证数据一致性

  • ✅ 支持非锁定一致性读

​​​​性能代价​​​​:

  • ⚠️ Undo Log 存储开销

  • ⚠️ 版本链遍历成本

  • ⚠️ 定期清理历史版本

🛠️ 最佳实践建议

​​​​设计优化​​​​:

-- 1. 控制事务时长,减少版本链长度
START TRANSACTION;
-- 快速操作
COMMIT;-- 2. 避免长时间未提交的事务
-- 长时间事务会导致大量历史版本积累-- 3. 定期清理过期数据
OPTIMIZE TABLE products; -- 重建表,清理旧版本

​​监控与调优​​:

-- 监控Undo Log使用
SHOW ENGINE INNODB STATUS;-- 查看历史版本数量
SELECT * FROM information_schema.INNODB_TRX;-- 监控长事务
SELECT * FROM information_schema.PROCESSLIST 
WHERE TIME > 60 AND COMMAND = 'Query';

⚠️ 注意事项

​​MVCC 局限性​​:

  • ❌ 不解决更新丢失问题

  • ❌ 不完全解决幻读问题

  • ❌ 需要额外的存储空间

​​版本清理策略​​

# my.cnf 配置
[mysqld]
innodb_undo_log_truncate = ON      # 开启undo log清理
innodb_max_undo_log_size = 1G      # 最大undo log大小
innodb_purge_batch_size = 300      # 清理批次大小

🔮 进阶技巧

​​查看版本信息​​:

-- 8.0+ 版本可以查询历史版本信息
SELECT * FROM products 
FOR SYSTEM_TIME 
AS OF TIMESTAMP '2023-01-01 00:00:00'
WHERE id = 1;

​​性能优化配置​​

# 针对MVCC的优化
innodb_read_only = OFF
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = ON
http://www.dtcms.com/a/394709.html

相关文章:

  • 决策树习题
  • PHP-ThinkPhp漏洞学习-MVC模型路由访问模版渲染安全写法版本漏洞(2024小迪安全Day31)
  • [已修复] iTunes 无法识别您的 iPhone
  • EC2 实例的操作系统 (OS) 未能成功从 AWS 的网络服务 (DHCP) 中获取到分配给它的私有 IPv4 地址
  • Vercel、Netlify、AWS 与 Cloudflare:前端部署与边缘计算平台全景对比
  • 【Threejs】【工具类】Raycaster实现 3D 交互(如鼠标拾取、碰撞检测)的核心工具
  • Fay数字人QA功能详解
  • NETSTAT命令详解
  • FFmpeg 5.x 编译 so 文件的记录
  • 以开启https的nginx转发流量到minio
  • StarRocks 各类索引以及存储位置详解
  • PromptPilot 技术深解,工程化提示词开发如何让大模型准确率大大提高
  • RTX4090:AI与深度学习应用实践的革命性推动者
  • Cursor Multi-Root Workspace 新特性深度实战:一次打开 React 前端 + Go 后端,AI 自动跨项目跳转、联调、写代码!
  • 如何处理单位换算的问题
  • Docker部署 MySQL+Mycat
  • RTX4090:极致性能探索与硬核评测
  • DM物理存储结构及内存结构
  • ASP.NET Core MVC 路由逻辑初探
  • 【Python办公】文字转视频(可自定义颜色、字体大小)
  • 数据洪流时代,如何挑选一款面向未来的时序数据库?IoTDB 的答案
  • python+django/flask的吉安红色旅游平台 红色教育景区展示+图文资讯发布+评论互动功能系统java+nodejs
  • 设计模式(C++)详解——代理模式 (Proxy Pattern)(2)
  • 详解 Kubernetes 命令:kubectl exec -it nginx -- bash 及实战场景
  • Android挂机短信模板和多台手机同步短信模板
  • Solid Edge 转换为 IGS 全流程技术指南:含迪威模型网在线转换方案
  • 设计模式(C++)详解——代理模式 (Proxy Pattern)(1)
  • 聊聊AI agents MCP 开发
  • 【C++进阶】智能指针的使用及其原理
  • 极客天成让统一存储从云原生‘进化’到 AI 原生: 不是版本升级,而是基因重组