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

wordpress播放优酷成都网站优化哪家好

wordpress播放优酷,成都网站优化哪家好,哈尔滨广告设计公司有哪些,网站开发属于什么会计科目1.事务回滚的需求 我们说过 事务 需要保证 原子性 #xff0c;也就是事务中的操作要么全部完成#xff0c;要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况#xff0c;比如#xff1a; (1). 事务执行过程中可能遇到各种错误#xff0c;比如服务器本身的错误也就是事务中的操作要么全部完成要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况比如 (1). 事务执行过程中可能遇到各种错误比如服务器本身的错误操作系统错误甚至是突然断电导致的错误。 (2). 程序员可以在事务执行过程中手动输入 ROLLBACK 语句结束当前的事务的执行。 这两种情况都会导致事务执行到一半就结束但是事务执行过程中可能已经修改了很多东西为了保证事务的原子性我们需要把东西改回原先的样子这个过程就称之为 回滚 英文名 rollback 这样就可以造成一个假象这个事务看起来什么都没做所以符合 原子性 要求。 小时候我非常痴迷于象棋总是想找厉害的大人下棋赢棋是不可能赢棋的这辈子都不可能赢棋的又不想认输只能偷偷的悔棋才能勉强玩的下去。 悔棋 就是一种非常典型的 回滚 操作比如棋子往前走两步 悔棋 对应的操作就是向后走两步比如棋子往左走一步 悔棋 对应的操作就是向右走一步。数据库中的回滚跟 悔棋 差不多你插入了一条记录 回滚 操作对应的就是把这条记录删除掉你更新了一条记录 回滚 操作对应的就是把该记录更新为旧值你删除了一条记录 回滚 操作对应的自然就是把该记录再插进去。 从上边的描述中我们已经能隐约感觉到每当我们要对一条记录做改动时这里的 改动 可以指 INSERT 、DELETE 、 UPDATE 都需要留一手 —— 把回滚时所需的东西都给记下来。比方说 (1). 你插入一条记录时至少要把这条记录的主键值记下来之后回滚的时候只需要把这个主键值对应的记录删掉就好了。 (2). 你删除了一条记录至少要把这条记录中的内容都记下来这样之后回滚时再把由这些内容组成的记录插入到表中就好了。 (3). 你修改了一条记录至少要把修改这条记录前的旧值都记录下来这样之后回滚时再把这条记录更新为旧值就好了。 设计数据库的大叔把这些为了回滚而记录的这些东东称之为撤销日志英文名为 undo log 我们也可以土洋结合称之为 undo日志 。这里需要注意的一点是由于查询操作 SELECT 并不会修改任何用户记录所以在查询操作执行时并不需要记录相应的 undo日志 。在真实的 InnoDB 中 undo日志 其实并不像我们上边所说的那么简单不同类型的操作产生的 undo日志 的格式也是不同的不过先暂时把这些容易让人脑子糊的具体细节放一放我们先回过头来看看 事务id 是个神马玩意儿。 2.事务id 2.1.给事务分配id的时机 我们前边在唠叨 事务简介 时说过一个事务可以是一个只读事务或者是一个读写事务 (1). 我们可以通过 START TRANSACTION READ ONLY 语句开启一个只读事务。在只读事务中不可以对普通的表其他事务也能访问到的表进行增、删、改操作但可以对临时表做增、删、改操作。 (2). 我们可以通过 START TRANSACTION READ WRITE 语句开启一个读写事务或者使用 BEGIN 、 START TRANSACTION 语句开启的事务默认也算是读写事务。在读写事务中可以对表执行增删改查操作。 如果某个事务执行过程中对某个表执行了增、删、改操作那么 InnoDB 存储引擎就会给它分配一个独一无二的事务id 分配方式如下 (1). 对于只读事务来说只有在它第一次对某个用户创建的临时表执行增、删、改操作时才会为这个事务分配一个 事务id 否则的话是不分配 事务id 的。 我们前边说过对某个查询语句执行EXPLAIN分析它的查询计划时有时候在Extra列会看到Using temporary的提示这个表明在执行该查询语句时会用到内部临时表。这个所谓的内部临时表和我们手动用CREATE TEMPORARY TABLE创建的用户临时表并不一样在事务回滚时并不需要把执行SELECT语句过程中用到的内部临时表也回滚在执行SELECT语句用到内部临时表时并不会为它分配事务 id。 (2). 对于读写事务来说只有在它第一次对某个表包括用户创建的临时表执行增、删、改操作时才会为这个事务分配一个 事务id 否则的话也是不分配 事务id 的。 有的时候虽然我们开启了一个读写事务但是在这个事务中全是查询语句并没有执行增、删、改的语句那也就意味着这个事务并不会被分配一个 事务id 。 说了半天 事务id 有啥子用这个先保密哈后边会一步步的详细唠叨。现在只要知道只有在事务对表中的记录做改动时才会为这个事务分配一个唯一的 事务id 。 2.2.事务id是怎么生成的 这个 事务id 本质上就是一个数字它的分配策略和我们前边提到的对隐藏列 row_id 当用户没有为表创建主键和 UNIQUE 键时 InnoDB 自动创建的列的分配策略大抵相同具体策略如下 (1). 服务器会在内存中维护一个全局变量每当需要为某个事务分配一个 事务id 时就会把该变量的值当作 事务id 分配给该事务并且把该变量自增1。每当这个变量的值为 256 的倍数时就会将该变量的值刷新到系统表空间的页号为 5 的页面中一个称之为 Max Trx ID 的属性处这个属性占用 8 个字节的存储空间。 (2). 当系统下一次重新启动时会将上边提到的 Max Trx ID 属性加载到内存中将该值加上256之后赋值给我们前边提到的全局变量因为在上次关机时该全局变量的值可能大于 Max Trx ID 属性值。 这样就可以保证整个系统中分配的 事务id 值是一个递增的数字。先被分配 id 的事务得到的是较小的 事务id 后被分配 id 的事务得到的是较大的 事务id 。 2.3.trx_id隐藏列 我们前边唠叨 InnoDB 记录行格式的时候重点强调过聚簇索引的记录除了会保存完整的用户数据以外而且还会自动添加名为trx_id、roll_pointer的隐藏列如果用户没有在表中定义主键以及UNIQUE键还会自动添加一个名为row_id的隐藏列。所以一条记录在页面中的真实结构看起来就是这样的 其中的 trx_id 列其实还蛮好理解的就是某个对这个聚簇索引记录做改动的语句所在的事务对应的 事务id 而已此处的改动可以是 INSERT 、 DELETE 、 UPDATE 操作。至于 roll_pointer 隐藏列我们后边分析 3.undo日志的格式 为了实现事务的 原子性 InnoDB 存储引擎在实际进行增、删、改一条记录时都需要先把对应的 undo日志 记下来。一般每对一条记录做一次改动就对应着一条 undo日志 但在某些更新记录的操作中也可能会对应着2条 undo日志 这个我们后边会仔细唠叨。一个事务在执行过程中可能新增、删除、更新若干条记录也就是说需要记录很多条对应的 undo日志 这些 undo日志 会被从 0 开始编号也就是说根据生成的顺序分别被称为 第0号undo日志 、 第1号undo日志 、…、 第n号undo日志 等这个编号也被称之为 undo no 。 这些 undo日志 是被记录到类型为 FIL_PAGE_UNDO_LOG 对应的十六进制是 0x0002 忘记了页面类型是个啥的同学需要回过头再看看前边的章节的页面中。这些页面可以从系统表空间中分配也可以从一种专门存放 undo 日志 的表空间也就是所谓的 undo tablespace 中分配。不过关于如何分配存储 undo日志 的页面这个事情我们稍后再说现在先来看看不同操作都会产生什么样子的 undo日志 吧 为了故事的顺利发展我们先来创建一个名为 undo_demo 的表 CREATE TABLE undo_demo (id INT NOT NULL,key1 VARCHAR(100),col VARCHAR(100),PRIMARY KEY (id),KEY idx_key1 (key1) )EngineInnoDB CHARSETutf8;这个表中有3个列其中 id 列是主键我们为 key1 列建立了一个二级索引 col 列是一个普通的列。我们前边介绍 InnoDB 的数据字典时说过每个表都会被分配一个唯一的 table id 我们可以通过系统数据库 information_schema 中的 innodb_sys_tables 表来查看某个表对应的 table id 是什么现在我们查看一下 undo_demo 对应的 table id 是多少 从查询结果可以看出 undo_demo 表对应的 table id 为 1078先把这个值记住我们后边有用。 3.1.INSERT操作对应的undo日志 我们前边说过当我们向表中插入一条记录时会有 乐观插入 和 悲观插入 的区分但是不管怎么插入最终导致的结果就是这条记录被放到了一个数据页中。如果希望回滚这个插入操作那么把这条记录删除就好了也就是说在写对应的 undo 日志时主要是把这条记录的主键信息记上。所以设计 InnoDB 的大叔设计了一个类型为 TRX_UNDO_INSERT_REC 的 undo日志 它的完整结构如下图所示 根据示意图我们强调几点 (1). undo no 在一个事务中是从 0 开始递增的也就是说只要事务没提交每生成一条 undo日志 那么该条日志的 undo no 就增1。 (2). 如果记录中的主键只包含一个列那么在类型为 TRX_UNDO_INSERT_REC 的 undo日志 中只需要把该列占用的存储空间大小和真实值记录下来如果记录中的主键包含多个列那么每个列占用的存储空间大小和对应的真实值都需要记录下来图中的 len 就代表列占用的存储空间大小 value 就代表列的真实值。 当我们向某个表中插入一条记录时实际上需要向聚簇索引和所有的二级索引都插入一条记录。不过记录undo日志时我们只需要考虑向聚簇索引插入记录时的情况就好了因为其实聚簇索引记录和二级索引记录是一一对应的我们在回滚插入操作时只需要知道这条记录的主键信息然后根据主键信息做对应的删除操作做删除操作时就会顺带着把所有二级索引中相应的记录也删除掉。后边说到的DELETE操作和UPDATE操作对应的undo日志也都是针对聚簇索引记录而言的我们之后就不强调了。 现在我们向 undo_demo 中插入两条记录 BEGIN; # 显式开启一个事务假设该事务的id为100 # 插入两条记录 INSERT INTO undo_demo(id, key1, col) VALUES (1, AWM, 狙击枪), (2, M416, 步枪);因为记录的主键只包含一个 id 列所以我们在对应的 undo日志 中只需要将待插入记录的 id 列占用的存储空间长度 id 列的类型为 INT INT 类型占用的存储空间长度为 4 个字节和真实值记录下来。本例中会产生两条类型为TRX_UNDO_INSERT_REC 的 undo日志 : (1). 第一条 undo日志 的 undo no 为 0 记录主键占用的存储空间长度为 4 真实值为 1 。画一个示意图就是这样 (2). 第二条 undo日志 的 undo no 为 1 记录主键占用的存储空间长度为 4 真实值为 2 。画一个示意图就是这样与第一条 undo日志 对比 undo no 和主键各列信息有不同 为了最大限度的节省undo日志占用的存储空间和我们前边说过的redo日志类似设计InnoDB的大叔会给undo日志中的某些属性进行压缩处理具体的压缩细节我们就不唠叨了。 3.2.roll pointer隐藏列的含义 是时候揭开 roll_pointer 的真实面纱了这个占用 7 个字节的字段其实一点都不神秘本质上就是一个指向记录对应的 undo日志 的一个指针。比方说我们上边向 undo_demo 表里插入了2条记录每条记录都有与其对应的一条 undo日志 。记录被存储到了类型为 FIL_PAGE_INDEX 的页面中就是我们前边一直所说的 数据页 undo日志 被存放到了类型为 FIL_PAGE_UNDO_LOG 的页面中。效果如图所示 从图中也可以更直观的看出来 roll_pointer 本质就是一个指针指向记录对应的undo日志。不过这 7 个字节的 roll_pointer 的每一个字节具体的含义我们后边唠叨完如何分配存储 undo 日志的页面之后再具体说哈 3.2.DELETE操作对应的undo日志 我们知道插入到页面中的记录会根据记录头信息中的 next_record 属性组成一个单向链表我们把这个链表称之为 正常记录链表 我们在前边唠叨数据页结构的时候说过被删除的记录其实也会根据记录头信息中的next_record 属性组成一个链表只不过这个链表中的记录占用的存储空间可以被重新利用所以也称这个链表为 垃圾链表 。 Page Header 部分有一个称之为 PAGE_FREE 的属性它指向由被删除记录组成的垃圾链表中的头节点。为了故事的顺利发展我们先画一个图假设此刻某个页面中的记录分布情况是这样的这个不是 undo_demo 表中的记录只是我们随便举的一个例子 为了突出主题在这个简化版的示意图中我们只把记录的 delete_mask 标志位展示了出来。从图中可以看出 正常记录链表 中包含了3条正常记录 垃圾链表 里包含了2条已删除记录在 垃圾链表 中的这些记录占用的存储空间可以被重新利用。页面的 Page Header 部分的 PAGE_FREE 属性的值代表指向 垃圾链表 头节点的指针。假设现在我们准备使用 DELETE 语句把 正常记录链表 中的最后一条记录给删除掉其实这个删除的过程需要经历两个阶段 (1). 仅仅将记录的 delete_mask 标识位设置为 1 其他的不做修改其实会修改记录的 trx_id 、roll_pointer 这些隐藏列的值。设计 InnoDB 的大叔把这个阶段称之为 delete mark 。 把这个过程画下来就是这样 可以看到 正常记录链表 中的最后一条记录的 delete_mask 值被设置为 1 但是并没有被加入到 垃圾链表 。也就是此时记录处于一个 中间状态 跟猪八戒照镜子——里外不是人似的。在删除语句所在的事务提交之前被删除的记录一直都处于这种所谓的 中间状态 。 为啥会有这种奇怪的中间状态呢其实主要是为了实现一个称之为MVCC的功能哈哈稍后再介绍。 (2). 当该删除语句所在的事务提交之后会有专门的线程后来真正的把记录删除掉。所谓真正的删除就是把该记录从 正常记录链表 中移除并且加入到 垃圾链表 中然后还要调整一些页面的其他信息比如页面中的用户记录数量 PAGE_N_RECS 、上次插入记录的位置 PAGE_LAST_INSERT 、垃圾链表头节点的指针PAGE_FREE 、页面中可重用的字节数量 PAGE_GARBAGE 、还有页目录的一些信息等等。设计 InnoDB 的大叔把这个阶段称之为 purge 。 把 阶段二 执行完了这条记录就算是真正的被删除掉了。这条已删除记录占用的存储空间也可以被重新利用了。画下来就是这样 对照着图我们还要注意一点将被删除记录加入到 垃圾链表 时实际上加入到链表的头节点处会跟着修改 PAGE_FREE 属性的值。 页面的Page Header部分有一个PAGE_GARBAGE属性该属性记录着当前页面中可重用存储空间占用的总字节数。每当有已删除记录被加入到垃圾链表后都会把这个PAGE_GARBAGE属性的值加上该已删除记录占用的存储空间大小。PAGE_FREE指向垃圾链表的头节点之后每当新插入记录时首先判断PAGE_FREE指向的头节点代表的已删除记录占用的存储空间是否足够容纳这条新插入的记录如果不可以容纳就直接向页面中申请新的空间来存储这条记录是的你没看错并不会尝试遍历整个垃圾链表找到一个可以容纳新记录的点。如果可以容纳那么直接重用这条已删除记录的存储空间并且把PAGE_FREE指向垃圾链表中的下一条已删除记录。但是这里有一个问题如果新插入的那条记录占用的存储空间大小小于垃圾链表的头节点占用的存储空间大小那就意味头节点对应的记录占用的存储空间里有一部分空间用不到这部分空间就被称之为碎片空间。那这些碎片空间岂不是永远都用不到了么其实也不是这些碎片空间占用的存储空间大小会被统计到PAGE_GARBAGE属性中这些碎片空间在整个页面快使用完前并不会被重新利用不过当页面快满时如果再插入一条记录此时页面中并不能分配一条完整记录的空间这时候会首先看一看PAGE_GARBAGE的空间和剩余可利用的空间加起来是不是可以容纳下这条记录如果可以的话InnoDB会尝试重新组织页内的记录重新组织的过程就是先开辟一个临时页面把页面内的记录依次插入一遍因为依次插入时并不会产生碎片之后再把临时页面的内容复制到本页面这样就可以把那些碎片空间都解放出来很显然重新组织页面内的记录比较耗费性能。 从上边的描述中我们也可以看出来在删除语句所在的事务提交之前只会经历 阶段一 也就是 delete mark 阶段提交之后我们就不用回滚了所以只需考虑对删除操作的 阶段一 做的影响进行回滚。设计 InnoDB 的大叔为此设计了一种称之为 TRX_UNDO_DEL_MARK_REC 类型的 undo日志 它的完整结构如下图所示 特别注意一下这几点 (1). 在对一条记录进行 delete mark 操作前需要把该记录的旧的 trx_id 和 roll_pointer 隐藏列的值都给记到对应的 undo日志 中来就是我们图中显示的 old trx_id 和 old roll_pointer 属性。这样有一个好处那就是可以通过 undo日志 的 old roll_pointer 找到记录在修改之前对应的 undo 日志。比方说在一个事务中我们先插入了一条记录然后又执行对该记录的删除操作这个过程的示意图就是这样 从图中可以看出来执行完 delete mark 操作后它对应的 undo 日志和 INSERT 操作对应的 undo 日志就串成了一个链表。这个很有意思啊这个链表就称之为 版本链 现在貌似看不出这个 版本链 有啥用等我们再往后看看讲完 UPDATE 操作对应的 undo 日志后这个所谓的 版本链 就慢慢的展现出它的牛逼之处了。 (2). 与类型为 TRX_UNDO_INSERT_REC 的 undo日志 不同类型为 TRX_UNDO_DEL_MARK_REC 的 undo 日志还多了一个 索引列各列信息 的内容也就是说如果某个列被包含在某个索引中那么它的相关信息就应该被记录到这个 索引列各列信息 部分所谓的相关信息包括该列在记录中的位置用 pos 表示该列占用的存储空间大小用 len 表示该列实际值用 value 表示。所以 索引列各列信息 存储的内容实质上就是pos, len, value 的一个列表。这部分信息主要是用在事务提交后对该 中间状态记录 做真正删除的阶段二也就是 purge 阶段中使用的具体如何使用现在我们可以忽略 该介绍的我们介绍完了现在继续在上边那个事务id为 100 的事务中删除一条记录比如我们把 id 为1的那条记录删除掉 BEGIN; # 显式开启一个事务假设该事务的id为100 # 插入两条记录 INSERT INTO undo_demo(id, key1, col) VALUES (1, AWM, 狙击枪), (2, M416, 步枪); # 删除一条记录 DELETE FROM undo_demo WHERE id 1;这个 delete mark 操作对应的 undo日志 的结构就是这样 对照着这个图我们得注意下边几点 (1). 因为这条 undo 日志是 id 为 100 的事务中产生的第3条 undo 日志所以它对应的 undo no 就是 2 。 (2). 在对记录做 delete mark 操作时记录的 trx_id 隐藏列的值是 100 也就是说对该记录最近的一次修改就发生在本事务中所以把 100 填入 old trx_id 属性中。然后把记录的 roll_pointer 隐藏列的值取出来填入 old roll_pointer 属性中这样就可以通过 old roll_pointer 属性值找到最近一次对该记录做改动时产生的 undo日志 。 (3). 由于 undo_demo 表中有2个索引一个是聚簇索引一个是二级索引 idx_key1 。只要是包含在索引中的列那么这个列在记录中的位置 pos 占用存储空间大小 len 和实际值 value 就需要存储到 undo日志 中。 a. 对于主键来说只包含一个 id 列存储到 undo日志 中的相关信息分别是 pos id 列是主键也就是在记录的第一个列它对应的 pos 值为 0 。 pos 占用1个字节来存储。 len id 列的类型为 INT 占用4个字节所以 len 的值为 4 。 len 占用1个字节来存储。 value 在被删除的记录中 id 列的值为 1 也就是 value 的值为 1 。 value 占用4个字节来存储。 画一个图演示一下就是这样 所以对于 id 列来说最终存储的结果就是 0, 4, 1 存储这些信息占用的存储空间大小为 1 1 4 6 个字节。 b. 对于 idx_key1 来说只包含一个 key1 列存储到 undo日志 中的相关信息分别是 pos key1 列是排在 id 列、 trx_id 列、 roll_pointer 列之后的它对应的 pos 值为 3 。 pos 占用1个字节来存储。 len key1 列的类型为 VARCHAR(100) 使用 utf8 字符集被删除的记录实际存储的内容是 AWM 所以一共占用3个字节也就是所以 len 的值为 3 。 len 占用1个字节来存储。 value 在被删除的记录中 key1 列的值为 AWM 也就是 value 的值为 AWM 。 value 占用3个字节来存储。 画一个图演示一下就是这样 所以对于 key1 列来说最终存储的结果就是 3, 3, AWM 存储这些信息占用的存储空间大小为 1 1 3 5 个字节。 从上边的叙述中可以看到 0, 4, 1 和 3, 3, AWM 共占用 11 个字节。然后 index_col_info len 本身占用 2 个字节所以加起来一共占用 13 个字节把数字 13 就填到了 index_col_info len 的属性中。 3.3.UPDATE操作对应的undo日志 在执行 UPDATE 语句时 InnoDB 对更新主键和不更新主键这两种情况有截然不同的处理方案。 3.3.1.不更新主键的情况 在不更新主键的情况下又可以细分为被更新的列占用的存储空间不发生变化和发生变化的情况。 (1). 就地更新in-place update 更新记录时对于被更新的每个列来说如果更新后的列和更新前的列占用的存储空间都一样大那么就可以进行 就地更新 也就是直接在原记录的基础上修改对应列的值。再次强调一边是每个列在更新前后占用的存储空间一样大有任何一个被更新的列更新前比更新后占用的存储空间大或者更新前比更新后占用的存储空间小都不能进行 就地更新 。比方说现在 undo_demo 表里还有一条 id 值为 2 的记录它的各个列占用的大小如图所示因为采用 utf8 字符集所以 ‘步枪’ 这两个字符占用6个字节 假如我们有这样的 UPDATE 语句 UPDATE undo_demo SET key1 P92, col 手枪 WHERE id 2;在这个 UPDATE 语句中 col 列从 步枪 被更新为 手枪 前后都占用6个字节也就是占用的存储空间大小未改变 key1 列从 M416 被更新为 P92 也就是从 4 个字节被更新为 3 个字节这就不满足 就地更新 需要的条件了所以不能进行 就地更新 。但是如果 UPDATE 语句长这样 UPDATE undo_demo SET key1 M249, col 机枪 WHERE id 2;由于各个被更新的列在更新前后占用的存储空间是一样大的所以这样的语句可以执行 就地更新 。 (2). 先删除掉旧记录再插入新记录 在不更新主键的情况下如果有任何一个被更新的列更新前和更新后占用的存储空间大小不一致那么就需要先把这条旧的记录从聚簇索引页面中删除掉然后再根据更新后列的值创建一条新的记录插入到页面中。请注意一下我们这里所说的 删除 并不是 delete mark 操作而是真正的删除掉也就是把这条记录从 正常记录链表 中移除并加入到 垃圾链表 中并且修改页面中相应的统计信息比如 PAGE_FREE 、PAGE_GARBAGE 等这些信息。不过这里做真正删除操作的线程并不是在唠叨 DELETE 语句中做 purge 操作时使用的另外专门的线程而是由用户线程同步执行真正的删除操作真正删除之后紧接着就要根据各个列更新后的值创建的新记录插入。 这里如果新创建的记录占用的存储空间大小不超过旧记录占用的空间那么可以直接重用被加入到 垃圾链表 中的旧记录所占用的存储空间否则的话需要在页面中新申请一段空间以供新记录使用如果本页面内已经没有可用的空间的话那就需要进行页面分裂操作然后再插入新记录。 针对 UPDATE 不更新主键的情况包括上边所说的就地更新和先删除旧记录再插入新记录设计 InnoDB 的大叔们设计了一种类型为 TRX_UNDO_UPD_EXIST_REC 的 undo日志 它的完整结构如下 其实大部分属性和我们介绍过的 TRX_UNDO_DEL_MARK_REC 类型的 undo日志 是类似的不过还是要注意这么几点 (1). n_updated 属性表示本条 UPDATE 语句执行后将有几个列被更新后边跟着的 pos, old_len, old_value 分别表示被更新列在记录中的位置、更新前该列占用的存储空间大小、更新前该列的真实值。 (2). 如果在 UPDATE 语句中更新的列包含索引列那么也会添加 索引列各列信息 这个部分否则的话是不会添加这个部分的。 现在继续在上边那个事务id为100的事务中更新一条记录比如我们把id为2的那条记录更新一下 BEGIN; # 显式开启一个事务假设该事务的id为100 # 插入两条记录 INSERT INTO undo_demo(id, key1, col) VALUES (1, AWM, 狙击枪), (2, M416, 步枪); # 删除一条记录 DELETE FROM undo_demo WHERE id 1; # 更新一条记录 UPDATE undo_demo SET key1 M249, col 机枪 WHERE id 2;这个 UPDATE 语句更新的列大小都没有改动所以可以采用 就地更新 的方式来执行在真正改动页面记录时会先记录一条类型为 TRX_UNDO_UPD_EXIST_REC 的 undo日志 长这样 对照着这个图我们注意一下这几个地方 (1). 因为这条 undo日志 是 id 为 100 的事务中产生的第4条 undo日志 所以它对应的 undo no 就是3。 (2). 这条日志的 roll_pointer 指向 undo no 为 1 的那条日志也就是插入主键值为 2 的记录时产生的那条 undo日志 也就是最近一次对该记录做改动时产生的 undo日志 。 (3). 由于本条 UPDATE 语句中更新了索引列 key1 的值所以需要记录一下 索引列各列信息 部分也就是把主键和 key1 列更新前的信息填入。 3.3.2.更新主键的情况 在聚簇索引中记录是按照主键值的大小连成了一个单向链表的如果我们更新了某条记录的主键值意味着这条记录在聚簇索引中的位置将会发生改变比如你将记录的主键值从1更新为10000如果还有非常多的记录的主键值分布在 1 ~ 10000 之间的话那么这两条记录在聚簇索引中就有可能离得非常远甚至中间隔了好多个页面。针对 UPDATE 语句中更新了记录主键值的这种情况 InnoDB 在聚簇索引中分了两步处理 (1). 将旧记录进行 delete mark 操作 高能注意这里是delete mark操作这里是delete mark操作这里是delete mark操作也就是说在 UPDATE 语句所在的事务提交前对旧记录只做一个 delete mark 操作在事务提交后才由专门的线程做purge操作把它加入到垃圾链表中。这里一定要和我们上边所说的在不更新记录主键值时先真正删除旧记录再插入新记录的方式区分开 之所以只对旧记录做delete mark操作是因为别的事务同时也可能访问这条记录如果把它真正的删除加入到垃圾链表后别的事务就访问不到了。这个功能就是所谓的MVCC我们后边的章节中会详细唠叨什么是个MVCC。 (2). 根据更新后各列的值创建一条新记录并将其插入到聚簇索引中需重新定位插入的位置。 由于更新后的记录主键值发生了改变所以需要重新从聚簇索引中定位这条记录所在的位置然后把它插进去。 针对 UPDATE 语句更新记录主键值的这种情况在对该记录进行 delete mark 操作前会记录一条类型为TRX_UNDO_DEL_MARK_REC 的 undo日志 之后插入新记录时会记录一条类型为 TRX_UNDO_INSERT_REC 的 undo日志 也就是说每对一条记录的主键值做改动时会记录2条 undo日志 。这些日志的格式我们上边都唠叨过了就不赘述了。 其实还有一种称为TRX_UNDO_UPD_DEL_REC的undo日志的类型我们没有介绍主要是想避免引入过多的复杂度如果大家对这种类型的undo日志的使用感兴趣的话可以额外查一下别的资料。
http://www.zqtcl.cn/news/853270/

相关文章:

  • 网站开发主要内容站长之家网站查询
  • 网站推广优化排名公司wordpress添加说说
  • 维护一个网站要多少钱企业怎么做网站
  • 怎么做兼职网站成都必去十大网红景点
  • 网站建设如何传视频教程电脑网站设计公司
  • 网站开发培训教程制作网站开发公司
  • 网站前端做报名框代码seo教育培训机构
  • 做网站要学习什么分销网站
  • 镇江市住房和城乡建设局网站常州建设网站
  • 学做美食的网站男女做暖暖到网站
  • 手机的网站建设目标刚做的网站 搜不到
  • 重庆网站建设哪里比较好呢ps怎么做网站logo
  • 网站建设五项基本原则优化关键词的公司
  • 高端网站的特点p2p网站开发的流程
  • 什么网站做外贸最好坪地网站建设公司
  • 做网站费用怎么核算没有公司 接单做网站
  • 如何建设一个优秀的电商网站wordpress注册去掉电子邮件
  • 站长工具 seo综合查询长沙高校网站制作公司
  • 杭州网站定制开发哪家好wordpress重置
  • 哈尔滨市建设安全网站火车头更新wordpress
  • 做亚马逊外国网站需要语言好吗邢台seo
  • jsp在网站开发中的优势国内哪个推广网站做的好
  • 做网站工资高吗精品资料
  • 做农业需关注什么网站热门代理项目
  • 网站开发公司营业范围照片制作视频软件app
  • 做网站怎么qq邮箱验证免费拥有wordpress
  • 校园网站建设资金来源有wordpress权重
  • 魔站网站开发wordpress 3.3.1
  • 东莞个人免费建网站网站后台管理系统 asp
  • 呼和浩特网站制作 建设wordpress怎么改中文