1、mvcc 多版本控制(可重复读隔离级别)
在Mysql中MVCC是在Innodb存储引擎中得到支持的,Innodb为每行记录都实现了三个隐藏字段:
(1)、事务ID(DB_TRX_ID 6-byte ):最新插入或修改行的事务ID,删除是特殊的修改,会有1bit标示;InnoDB内部维护了一个递增的tx id counter,其当前值可以通过show engine innodb status获得
(2)、回滚指针(DB_ROLL_PTR 7-byte):指向回滚日志的undo log
(3)、隐藏的ID 6-byte
当事务更改某行的值时,操作如下:
(1)、用排他锁锁定该行
(2)、记录redo log
(3)、把该行修改前的值Copy到undo log
(4)、修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行
(5)、如果事务1最后执行COMMIT操作,则什么操作都不用做。如果执行ROLLBACK操作,则需要通过回滚指针从undo log中还原修改前的数据。
(6)、释放该行的排它锁
=====================================================================
read view 判断当前版本数据项是否可见:
在InnoDB中,创建一个新事务的时候,InnoDB会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),副本中保存的是系统当前不应该被本事务看到的其他事务id列表。
当用户在这个事务中要读取该行记录的时候,InnoDB会将该行当前的版本号与该read view进行比较。
注:新建事务(当前事务)与正在内存中commit 的事务不在活跃事务链表中。
函数:read_view_sees_trx_id。
read_view中保存了当前全局的事务的范围:【low_limit_id, up_limit_id】
当行记录的事务ID小于当前系统的最小活动id,就是可见的。
if (trx_id < view->up_limit_id) {
return(TRUE);
}
当行记录的事务ID大于当前系统的最大活动id(也就是尚未分配的下一个事务的id),就是不可见的。
if (trx_id >= view->low_limit_id) {
return(FALSE);
}
当行记录的事务ID在活动范围之中时,判断是否在活动链表中,如果在就不可见,如果不在就是可见的。
for (i = 0; i < n_ids; i++) {
trx_id_t view_trx_id = read_view_get_nth_trx_id(view, n_ids - i - 1);
if (trx_id <= view_trx_id) {
return(trx_id != view_trx_id);
}
}
理想状态下,事务1的事务id=1,事务2的事务id=2。因为事务2执行时查询时,事务1正处于事务执行状态。
所以read view为{1},事务2读取的数据行 trx_id=1,read view中最早的事务id为trx_id_min=1, 最迟的事务id为trx_id_max=1。
因为trx_id_min <= trx_id <= trx_id_max,并且trx_id_min = trx_id = trx_id_max,说明该行记录所在事务在本次新事务创建的时候处于活动状态,不可见。
所以从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号的数据,将该可见行的值返回。所以不会出现脏读的现象。
=====================================================================
InnoDB行锁:
是通过索引上的索引项来实现的,通过在数据中对相应数据行加锁来实现的。
InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
Mysql中的间隙锁:
1、间隙划分;
2、间隙锁锁定区域,根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B);
3、间隙锁的目的是为了防止幻读:
(1)防止间隙内有新数据被插入;
(2)防止已存在的数据,更新成间隙内的数据(例如防止numer=3的记录通过update变成number=5);
4、nnodb自动使用间隙锁的条件:
(1)必须在RR级别下;
(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加);
有疑问加站长微信联系(非本文作者))

四种安全隔离级别:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
MyISAM与InnoDB区别: 链接:🔗https://www.jianshu.com/p/a957b18ba40d
1、 存储结构
MyISAM:每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。 InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。
2、 存储空间
MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。 InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
3、 可移植性、备份及恢复
MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。 InnoDB:免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。
4、 事务支持 MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。 InnoDB:提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
5、表锁差异
MyISAM:只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。 InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
6、CURD操作
MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。 InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令。
Limit的执行效率高,是对于一种特定条件下来说的:即数据库的数量很大,但是只需要查询一部分数据的情况。 高效率的原理是:避免全表扫描,提高查询效率。
比如:每个用户的email是唯一的,如果用户使用email作为用户名登陆的话,就需要查询出email对应的一条记录。 SELECT FROM t_user WHERE email=?; 上面的语句实现了查询email对应的一条用户信息,但是由于email这一列没有加索引,会导致全表扫描,效率会很低。 SELECT FROM t_user WHERE email=? LIMIT 1; 加上LIMIT 1,只要找到了对应的一条记录,就不会继续向下扫描了,效率会大大提高。
使用limit效率低,那就是:只使用limit来查询语句,并且偏移量特别大的情况
做以下实验: 语句1: select from table limit 150000,1000; 语句2: select from table while id>=150000 limit 1000; 语句1为0.2077秒;语句2为0.0063秒 两条语句的时间比是:语句1/语句2=32.968
where...limit....性能基本稳定,受偏移量和行数的影响不大,而单纯采用limit的话,受偏移量的影响很大,当偏移量大到一定后性能开始大幅下降。不过在数据量不大的情况下,两者的区别不大。