失效链接处理 |
多版本并发控制原理(MVCC) PDF 下载
本站整理下载:
提取码:u3dj
相关截图:
主要内容:
12 多版本并发控制原理(MVCC)
何登成 博客:https://blog.csdn.net/shaochenshuo/article/details/76137652
隔离性页可以被称作并发控制、可串⾏化等。谈到并发控制⾸先想到的就是锁,mysql通过使⽤两阶段锁的⽅式实
现了更新
的可串⾏化,同时为了加速查询性能,采⽤了MVCC(Multi Version Concurrency Control)的机制,使得不⽤锁也
可以获取⼀
致性的版本,innodb 为了实现多版本的⼀致性读,采⽤的是基于回滚段的协议。
⾏结构
innoDB 表数据的组织⽅式为主键聚簇索引。由于采⽤索引组织表结构,记录的ROWID是可变的(索引页分裂的时
候,
Structure Modification Operation, SMO),因此⼆级索引中采⽤的是(索引值,主键值)的组合来唯⼀确定⼀条记
录。
⽆论是聚簇索引,还是⼆级索引,其每条记录都包含了⼀个DELETED BIT位,⽤于标识该记录是否是删除记录。
除此之外,
聚簇索引记录还有两个系统列(隐藏列):DATA_TRX_ID,DATA_ROLL_PTR。
DATA_TRX_ID:表⽰产⽣当前记录的事务ID
DATA_ROLL_PTR:是指针,指向当前及录像的undo信息
结构如下:
undo
undo ⽇志保存在回滚段中,回滚段在ibdata或单独的undo tablespace中。
undo 记录的主要类型如下,其中TRX_UNDO_INSERT_REC为insert的undo,其他为upadte和delete的undo
1 #define TRX_UNDO_INSERT_REC 11 /* fresh insert into clustered index */
2 #define TRX_UNDO_UPD_EXIST_REC \
3 12 /* update of a non-delete-marked \
4 record */ 5 #define TRX_UNDO_UPD_DEL_REC \
6 13 /* update of a delete marked record to \
7 a not delete marked record; also the \
8 fields of the record can change */ 9 #define TRX_UNDO_DEL_MARK_REC \
10 14 /* delete marking of a record; fields \
11 do not change */
对应insert和delete,undo中会记录键值,delete操只是标记删除(delete mark)记录。对于update,如果
是原地更新,undo中会记录键值和⽼的值
update 如果是通过delete+insert⽅式进⾏的,则undo中记录键值,不需要记录⽼的值。其中delete也是标记
删除记录。⼆级索引的更新总是delete+insert的⽅式进⾏。具体⽇志格式参看trx_undo_report_row_operation.
MVCC(实现机制)
注意:MVCC仅仅在纯select时有效(不包括select for update, lock in share mode等加锁操作,以及update\insert
等)
⾸先我们跟踪⼀下⼀条普通的查询sql在mysql源码中的运⾏过程,sql为(select * from test);
其运⾏栈为:
1 handle_one_connection MySQL的⽹络模型是one request one thread
2 |-do_handle_one_connection
3 |-do_command
4 |-dispatch_command
5 |-mysql_parse 解析SQL
6 |-mysql_execute_command
7 |-exe···cute_sqlcom_select 执⾏select语句 8 |-handle_select
9 ...⼀堆parse join 等的操作,当前并不关⼼
10 |-*tab->read_record.read_record 读取记录
由于mysql默认隔离级别是repeatable_read(RR),所以read_record重载为 rr_sequential(当前我们并不关⼼select
通过index扫描出row之后再通过condition过滤的过程)。继续追踪: 1 read_record
2 |-rr_sequential
3 |-ha_rnd_next
4 |-ha_innobase::rnd_next 这边就已经到了innodb引擎了 5 |-general_fetch
6 |-row_search_for_mysql
7 |-lock_clust_rec_cons_read_sees 这边就是判断并选择版本的地⽅
看看函数内部
1 bool lock_clust_rec_cons_read_sees(const rec_t* rec /*由innodb扫描出来的⼀⾏*/,....){ 2 ...
3 // 从当前扫描的⾏中获取其最后修改的版本trx_id(事务id)
4 trx_id = row_get_rec_trx_id(rec, index, offsets); 5 // 通过参数(⼀致性快照视图和事务id)决定看到的⾏快照 6 return(read_view_sees_trx_id(view, trx_id)); 7 }
|