doc: 阅读mysql mvcc文档
This commit is contained in:
@@ -1 +1,64 @@
|
|||||||
# mysql mvcc
|
# mysql mvcc
|
||||||
|
innodb是一个`多版本`的存储引擎,对于被修改的records,其保存了records旧版本的信息,从而支持事务的`并发`和`回滚`等特性。
|
||||||
|
|
||||||
|
innodb使用了rollback segment中存储的信息来进行`undo操作`,从而`支持事务在需要时进行回滚`;`并且支持通过undo信息构建record的早期版本,从而实现一致性读`。
|
||||||
|
|
||||||
|
## Internal Impl
|
||||||
|
在innodb的内部实现中,其为数据库中存储的每行数据都额外添加了3个字段:
|
||||||
|
- `DB_TRX_ID`:长度为6字节,用于标识`最后对改行数据进行insert/update操作的事务`
|
||||||
|
- 其中,delete操作也被看做是`update`,因为innodb在对数据执行删除操作时,并不会立马对数据进行物理删除,而是会先标记该行数据的delete mark,数据实际被物理删除发生在purge阶段
|
||||||
|
- `DB_ROLL_PTR`:长度为7字节,被称为`roll pointer`。该指针指向undo record,通过undo record中的内容可以构建该行数据被更新前的版本
|
||||||
|
- `DB_ROW_ID`:长度为6字节,该字段包含一个row id,该row id在数据被插入时会单调的增长。
|
||||||
|
- 如果表使用的是innodb自动生成的聚簇索引(未显式指定主键),那么自动生成的聚簇索引将会包含该row id的值
|
||||||
|
- 如果表显式指定了聚簇索引,那么`DB_ROW_ID`并不会出现在任何索引中
|
||||||
|
|
||||||
|
## undo log
|
||||||
|
在rollback segment中,undo log可以分为两种类型:
|
||||||
|
- insert undo log
|
||||||
|
- update undo log
|
||||||
|
|
||||||
|
### insert undo log
|
||||||
|
insert undo log只会在事务回滚时被用到,在事务提交之后,insert undo log的内容可以被立马删除。
|
||||||
|
|
||||||
|
### update undo log
|
||||||
|
update undo log除了用于事务回滚外,还用于一致性读(MVCC)。对于update undo log,其只在满足如下条件时可以被删除
|
||||||
|
- 当`需要通过该update undo log来构建数据先前版本`的事务都不存在时,update undo log才可以被删除
|
||||||
|
|
||||||
|
> innodb会为每个事务分配一个快照,事务在进行一致性读时,实际读取的是快照中的旧版本数据。
|
||||||
|
>
|
||||||
|
> 快照需要通过update undo log来还原行数据的旧版本。如果没有事务再需要通过该update undo log来还原旧数据,代表该update undo log可以被删除。
|
||||||
|
|
||||||
|
### commit regularly
|
||||||
|
在编写和数据库交互的代码时,推荐周期性的提交事务,`包括只会进行一致性读的读事务`。如果事务A的运行时间较长,且一直未提交,那么在事务A运行时,其他事务对数据库的更新操作,其生成的update undo log在事务A运行期间都无法被丢弃(因为有可能A会读取被修改数据之前的版本,此时需要通过undo update log来进行旧版本数据的还原)。
|
||||||
|
|
||||||
|
故而,如果存在一直不提交的事务,那么可能会造成update undo log无法丢弃,那么rollback segment占用的空间大小会不断增加,填满其所位于的undo tablespace。
|
||||||
|
|
||||||
|
### purge
|
||||||
|
在innodb的mvcc方案中,在通过delete sql删除行数据后,行数据并不会立马就从该数据库中被移除(不会立马被物理删除)。
|
||||||
|
|
||||||
|
innodb直到`删除update undo log record时`才`删除undo log record关联的行数据/index records`。该删除操作被称为`purge`。
|
||||||
|
|
||||||
|
purge的操作很快,并且purge的顺序通常和执行delete sql的时间顺序相同。
|
||||||
|
|
||||||
|
### insert and delete rows in smallish batches
|
||||||
|
如果针对表同时执行insert和delete的小批量操作,且insert和delete的速率相同,那么purge现成的回收速率可能会小于数据的插入速率。这样会导致`dead rows`(标记为逻辑删除但未实际purge的数据行)堆积,表占用空间越来越大,并造成disk相关操作变慢。
|
||||||
|
|
||||||
|
在上述场景下,应当限制新操作,并且通过调整innodb_max_purge_lag向purge thread分配更多资源。
|
||||||
|
|
||||||
|
#### purge lag
|
||||||
|
##### innodb_purge_threads
|
||||||
|
purge操作在后台由一个或多个purge threads执行。purge threads的数量由`innodb_purge_threads`来进行控制,默认值的取值逻辑如下:
|
||||||
|
- 如果可获取的逻辑核数小于等于16,则默认值为1
|
||||||
|
- 如果logic processors大于16,那么默认值为4
|
||||||
|
|
||||||
|
当dml操作集中在一张表上,那么该表的purge操作由一个现成来执行,这样可能会造成purge操作变慢,增加purge lag。
|
||||||
|
|
||||||
|
##### innodb_max_purge_lag
|
||||||
|
如果purge lag超过`innodb_max_purge_lag`时,purge工作会自动在多个purge threads之间进行重新分配。
|
||||||
|
|
||||||
|
当purge threads设置过大时,可能会造成与user threads的争用,故而相当适当的管理purge threads大小。
|
||||||
|
|
||||||
|
`innodb_max_purge_lag`的默认值为0,代表默认不存在max purge lag。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user