InnoDB中的死锁因为不同的事务持有对方需要的锁 , 导致这些事务不能执行下去 。 由于每个事务都在等待资源变成可用 , 都不会释放它持有的锁 。
可能出现的场景:多个事务以不同的顺序锁定多个表中的行(通过类似这样的语句:UPDATE或SELECT … FOR UPDATE) , 锁定范围索引记录和间隙 , 每个事务因为时间的原因只获取一部分锁 。
为了减少死锁的可能 ,
- 使用事务而不是LOCK TABLES语句;
- 保持insert或update的事务足够小 , 让他们不会长时间打开;
- 当不同的事务更新多个表或者大范围的行 , 在每个事务里使用相同顺序的操作(例如SELECT … FOR UPDATE);
- 在SELECT … FOR UPDATE和UPDATE … WHERE 语句中使用到的列上创建好索引
- 如果使用锁定读(SELECT … FOR UPDATE或者SELECT … FOR SHARE) , 尝试使用例如READ COMMITTED这样的低隔离级别
- 添加选择度高的索引到表中 , 这样查询只需要扫描更少的索引记录 , 相应的也就设置更少的锁 。 使用EXPLAIN SELECT来查看
InnoDB多版本控制 MVCCInnoDB是一个多版本的存储引擎 。 它持有被更改过的行的旧版本信息 , 以支持例如并发和回滚这样的事务特性 。 这个信息存储在undo表空间里面一个叫rollback segment的数据结构中 。 InnoDB使用回滚段里的信息来执行事务回滚里面的undo操作 。 它还使用这信息来构建更早版本的行用于实现一致性读 。
InnoDB内部在数据库里存储的每个行里添加了三个字段:
- 6-byte DB_TRX_ID , 表示最近一个插入或更新行的事务的事务标识符 。 删除在内部也是被视为更新 , 行里面一个特定的bit会设置以标识它为已删除
- 7-byte DB_ROLL_PTR , 滚动指针 。 它指向回滚段里的一条undo日志记录 。 如果行被更新了 , 这条undo日志记录会包含更新前重建行所需要的必要信息
- 6-byte DB_ROW_ID , 包含了随着新行插入而单调递增的行ID 。 如果InnoDB自动生成了一个聚簇索引 , 索引会包含行ID的值 。 否则DB_ROW_ID列不会出现在任何索引里
建议定期提交事务 , 包括仅发出一致性读的事务 。 否则InnoDB不能从更新的undo日志里丢弃数据 , 这样回滚段可能会增长得太大 , 充满它驻留的整个undo表空间 。
回滚段里的undo日志记录的物理大小通常比相应的插入或更新行更小 。 可以使用这个信息来记录回滚段需要的空间 。
在InnoDB多版本控制方案中 , 当使用SQL语句删除的时候 , 该行并不会立即从数据库中物理删除 。 InnoDB仅在丢弃为删除而写入的更新undo日志的时候 , 才会物理删除相应的行和索引记录 。
多版本和二级索引InnoDB 多版本并发控制(MVCC)对待二级索引不同于聚簇索引 。 聚簇索引中的记录会就地更新 , 其隐藏的系统列指向undo日志项 , 从中可以重构早期版本的记录 。 二级索引不包含隐藏的系统列 , 也不进行就地更新 。
更新二级索引列时 , 旧的二级索引被删除标记 , 新记录被插入 , 删除标记的记录最终被清除 。 当二级索引记录被删除标记 , 或者二级索引页被更新的一个事务更新时 , InnoDB会在聚簇索引中查找数据库记录 。 在聚簇索引中 , 检查记录的DB_TRX_ID , 如果在读取事务启动后修改了记录 , 则从undo日志里检索出记录的正确版本 。
- 平时大家输入汉字时一般都习惯用拼音输入法|怎么在电脑上把不认识的字打出来
- Java|24位博主,带你了解自媒体的真相
- 华为|不同职业的人怎么选华为PC?带你对号入座
- 域名|认识松下Lumix DC-G95(G90)
- 骨传导耳机|骨传导耳机伤耳朵吗?带你一分钟了解骨传导耳机
- 华硕|双12大促来了!带你种草全新华为“书房三宝”
- 北大|北大天才少年“还俗僧人”柳智宇宣布恋情:出家时就认识她了 女方未提买房买车
- 数学|北大数学天才柳智宇还俗后宣布恋情:出家时就认识她了 符合找女友标准
- 短视频|【海归求职网CareerGlobal】13年500强企业工作经验资深行业顾问带你深入了解产品经理岗位!
- 燃气热水器|双增压零冷水,这冬天云米AI燃气热水器Super带你酣畅淋漓地洗澡
