InnoDB Multi-Versioning

InnoDB Multi-Versioning

InnoDB是一个多版本的存储引擎,他通过保存被修改的行的老版本来支持事务的特性,例如并发与回滚。这些信息存储在表空间里被叫做回滚段的数据结构中。InnoDB使用回滚段中的信息来执行事务回滚中必要的回滚操作。这些信息也被使用在一致性读取的时候创建数据的早期版本(与隔离级别有关)。

在内部,InnoDB为存储在数据库中的每一行添加三个条目。一个6字节的DB_TRX_ID标识最后一个事务的插入和更新,删除操作在内部被视为更新操作,在该行中的一个特殊的位被设置用来标识行被删除。每行还包含一个7字节的DB_ROLL_PTR滚动指针。这个滚动指针指向被写在回滚段中的一条Undo log记录。如果行被更新,Undo log中的这条记录在行被更新之前必须要重建内容(这里的意思是:在事务提交之前,即使行被改变也不会改变指针指向的Undo log记录,因为其他的事务可能访问该行原始的信息,需要从Undo log返回;在当前事务提交的时候,Undo log必须先更新,这样能保证之后的事务正常访问数据)。还有一个6字节的DB_ROW_ID,他包含一个行ID,在有新行插入的时候增加。如果InnoDB自动生成聚簇索引,那么索引也会包含这个ID值,否则DB_ROW_ID不会出现在任何索引中。

在回滚段中的Undo logs被分为插入Undo logs和更新Undo logs。插入Undo logs只在事务被回滚的时候使用,当事务提交就被丢弃。更新Undo log也被使用在一致性读取上,仅在没有事务的情况下被丢弃,InnoDB指定一个镜像,这个镜像包含在一致性读取中可能需要的更新Undo log创建的数据行的早期版本。

回滚段中的Undo log物理空间大小一般比相应插入或更新的行小。你可以通过这些信息计算你的回滚段需要的空间大小。

在InnoDB多版本模式下,执行删除语句不会立即物理删除数据库中的行。仅当因为删除操作写入更新undo log日志里面的记录被丢弃的时候,InnoDB会物理删除相应的行和索引记录。这种删除操作称为purge,他是非常快的,通常与执行删除操作的时间顺序相同。

如果一张表有同样概率的小批量插入和删除,由于所有的‘dead’行,making everything disk-bound(大概是:使所有的已标记为删除的行对应到更新Undo log都是跳跃的,不连续的),并且非常慢,这时候purge会开始落后,并且表会变的越来越大。在这种情况下,需要控制新行的插入,并且需要通过调节innodb_max_purge_lag系统变量来为pruge线程分配更多资源。

多版本与辅助索引

InnoDB多版本并发控制与聚簇索引对待辅助索引是不同的,在聚簇索引中的记录会立即更新,他们的系统隐藏列指向Undo log里面这个列的能被重建的早期版本。不像聚簇索引,辅助索引不包含系统隐藏列,也不会被立即更新。

当一个辅助索引列被更新,老的辅助索引列被标记为删除,新的纪录被插入,被标记为删除的记录最终会被purge。当辅助索引被标记为删除或被一个新的事务更新,InnoDB通过聚簇索引查找数据。在聚簇索引上,如果记录在读事务开始之后被修改,记录的DB_TRX_ID被检查,正确版本的记录会从Undo log返回。

如果辅助索引记录被标记为删除或者被新的事务更新,那么覆盖索引技术不能使用。取而代之的是从索引结构返回数据,InnoDB从聚簇索引中重找记录。

然而,如果index condition pushdown(ICP)优化被启用,where条件会被索引中单独的列进行评估,MySQL服务始终将这部分where条件推到存储引擎层面,在这里使用索引进行评估。如果没有记录被匹配,聚簇索引扫描就被避免了。如果有记录被匹配,被标记为删除的记录也算,InnoDB通过聚簇索引查找记录。

下面是相关知识点的具体介绍:

Undo logs

Undo log是与单个事务相关的Undo log记录的集合。Undo log记录包含如何从最新变更撤销到聚簇索引记录(指的是之前的数据库记录)的信息。 如果其他的事务需要查询原始数据(作为一致性读取的一部分),未修改的数据从Undo log返回。

聚簇索引

聚簇索引是主键索引的InnoDB术语,InnoDB表的存储是基于主键值进行组织的(索引组织表),用来加速涉及到主键的查询和排序。为了更好的性能,应该基于最关键的查询认真的选择索引。因为更改聚簇索引列是昂贵的操作,所以选择主键列rarely或者不进行更新。

辅助索引

InnoDB索引的一种类型,代表了表列的子集。InnoDB表可以没有也可以有一个或多个辅助索引(聚簇索引每个表是必须的,并且存储了表中所有列的数据)。 辅助索引满足仅需要被索引列的值的查询。对于更复杂的查询,他能被用来确定表中相关的行,然后通过查询聚簇索引返回数据。 以往,创建和删除辅助索引涉及到复制数据的大量开销。现在的fast index creation特性使CREATE INDEX和DROP INDEX语句执行的更快。

聚簇索引与辅助索引

每个InnoDB表都有一个特殊的索引叫聚簇索引,他上面存储了每一行的数据。通常聚簇索引是主键索引的同义词。为了从查询、插入以及其他操作中获得更好的性能,你必须知道InnoDB是如何使用聚簇索引去优化每张表的查询和DML操作的。

  • 当你在InnoDB表上定义了主键,这个列就被作为聚簇索引。为每个你创建的表定义主键。如果你的表没有唯一的、非空的列,那么添加一个新的自增列,它的值会被自动添加上。
  • 如果你的表没有定义主键,MySQL会定位第一个UNIQUE的列(并且不能为空),InnoDB会使用它作为聚簇索引。
  • 如果表没有主键,也没有合适的UNIQUE列,InnoDB会在内部生成一个包含行ID的虚拟列。数据行通过ID列排序。这个ID是一个6字节的区域,当有新行插入的时候单调递增。因此, 数据行的顺序就是物理层面数据的插入顺X序。

聚簇索引如何加速查询

通过聚簇索引访问行是非常快的,因为索引搜索直接指向包含所有行数据的页。如果表非常大,聚簇索引的架构通常更省磁盘I/O(索引条目指向的行存储在不同的页)。

辅助索引与聚簇索引的关系

除了聚簇索引的其他索引都被叫做辅助索引。在InnoDB中,当列被指定为辅助索引的时候,在辅助索引中的每条记录都包含当前行的主键索引,InnoDB使用主键值搜索在聚簇索引上的行。 如果主键太长,那么相应的辅助索引也会占用更多的空间。所以一个短的主键是有好处的。

(完)