mysql总结

1、mysql的buffer pool
mysql中的数据以page页为单位,每个页都对应一个对象叫做控制块,每个控制块中含有页号,每个页号指向一个页。mysql中有三个列表,每个列表都是控制块的列表,分别是free list,lru list,flush list。
free list:根据设置的buffer pool的大小除以页的大小计算出来的页的数量,也即是控制块的数量,初始化一个链表。
lru list:当需要读取一个磁盘上的页的时候,就会找一个控制块,从free list中拿出来,加入到lru list中。这个链表分成两部分,一部分是冷数据,一部分是热数据,默认是三七分,冷数据占30%。当从磁盘读取一个page的时候,先加入到冷数据的header部分,如果后续该page还会被读取,就会写入到热数据中。热数据中保存的是访问特别频繁的数据,所以如果每次访问都移动到链表的header是很耗费性能的,所以规定了在热数据中只有后25%的数据的访问才会写入到header,前75%的page的访问是不移动的。分成冷热数据的原因是为了防止全表扫描的情况,全表扫描时会把所有的page都加载一遍,如果没有冷热之分,那么就会把热数据全部删掉,而有了区分,热数据不会受影响。如果一个冷数据的页面因为偶然的因素被连续读取了多次,那么也不会写入到热数据的,mysql中有一个时间的限制,在一秒以内的多次读取算作一次读取,这也是防止全表扫描带来的问题。
flush list:当一个page页发生了修改以后,该page页不会立刻刷新到磁盘,而是记录了redo log来做持久化。此时这个页是一个脏页,就会写入到flush list中,等以后做刷脏,刷脏的时候就会从flush list中读取页面然后持久化到磁盘中。一个脏页加入到链表中,只会写入一次,第二次写入的时候如果发现已经在flush list中了,就不会再次写入,所以不会移动位置。

2、mysql为什么要写redolog
mysql中的数据以page页为单位,每个页的大小是16k,一次修改操作可能修改的很少,如果每次修改都要强制刷新一个页,性能太差,而redo log记录的增量,改动少的时候记录的也很少,所以效率更高;第二个,redo log采用的是顺序写,直接在redo log的最后追加,而刷新一个page页需要找到页在磁盘的位置,要涉及到随机读,性能较差。
总结:1是数据量的问题;2是顺序写和随机写的问题。

3、为什么redolog要先写,即wal
这里的wal指的是将page页写磁盘,并不是写内存中的page页。每个事务在提交的时候都是先持久化redo log,是因为redo log数据量不会太大,第二个是顺序写,和上面的逻辑一样。

3、redo log会一直写吗?不会无线大吗?
redo log如果一直写的话会特别的大,而且mysql会有刷脏的操作,刷脏后,过早的redo log就会变得无用,所以innodb会有擦除redo log的行为,叫做check point。
每一个redo log都有一个编号叫做lsn(log sequence number),是一个递增的数字,每一个被修改的page页上都会记录最早修改的redo log的lsn和最新修改的lsn,分别叫做oldeds modification和newest modification,在写入flush list的时候,是按照oldest modification排序的,有一个页被修改的时候是写在链表的头部,所以整个flush list是按照oldest modification倒排序的,最新修改的page也在header,在更新一个已经在flush list中的page的时候,只会更新其newest modification。
每隔一段时间,mysql就会做一次check point,check point的意思是这样的:选择flush list的最后一个page的oldest modification,记作a,因为这个是flush list的最后一个page,其前面的page的更新的redo log的lsn肯定都大于a,所以redo log中所有小于a的都可以舍弃不用了,也就是可以删除了。记录这个值a就叫做check point lsn,这个值会写入再redo log的文件中。redo log文件一共有两个,因为有擦除,所以可以循环着来写。因为每次做check point会写磁盘,所以不是每次更新都会做check point的。

4、redo log是怎么存储的
redo log是先存储在内存中,叫做redo log buffer,然后有一个后端线程,每一秒钟会强制刷新一次redo log倒磁盘中,另外在事务提交的时候也会写磁盘(根据innod_flush_log_at_trx_commit的配置)。
innod_flush_log_at_trx_commit可以配置为0,1,2。0的时候表示提交的时候不写redo log buffer到redo log file中,而是只依赖定时任务持久化;1的时候表示提交的时候写redo log file,同时调用操作系统的fsync方法将改动持久化;2表示提交的时候写redo log file,但是只交给操作系统而不调用fsync方法做持久化,依赖于定时任务做持久化。
在磁盘上mysql分为两个文件,因为有擦除,所以两个文件可以循环写入。

5、什么时候刷脏,刷脏时只刷一个吗?
mysql的刷脏有三种方式1.后台线程会不断从flush list的尾巴部分刷脏;2.后台线程会检查free list,保证有充足的free list节点方便用户操作从磁盘加载page页面的时候会空闲的位置,所以当free list特别少的时候,会将lru list中的冷数据的部分中的页删除,如果页恰好是脏页就会做刷脏,将控制块还回到free list中;3.用户线程如果从磁盘中读取特别多的数据然后发现没有可用的free list,就会从lru list的冷数据中删除页面,如果页面恰好是脏页就会触发刷脏,此时就会影响用户线程的执行。
刷脏的时候会有连坐发生,因为要进行io,mysql会检查是否临近的也都是脏页,如果是则会都刷脏。

6、undo log是什么?
undo log是记录的修改之前的数据。在发生写操作的时候,是直接在数据上做的修改,但是为了做事务的回滚,则要记录修改之前的数据,这就是undo log。每一条数据有两个隐藏列,一个是事务id,一个是roll_pointer,当更新一条数据的时候,先在undo page中记录undo log,同时更新数据上的roll_pointer指向刚写的undo log。如果更新多次,就会有多个undo log,构成一个版本链。
一个事务的undo log有两种类型,一种是insert类型的,一种是update类型的(针对于update和delete操作),之所以将他们分开是因为insert类型的不用保存,他之前的数据不存在,所以不用保留之前的数据,只要事务提交了undo log就可以抛弃不要了。每一种类型的都是一个list,mysql中存在一个东西叫做回滚段,每个回滚段中只有一个页面,该页中含有1024个undo slot,他的原始值是fil_null,当写undo log的时候,会从undo slot中查找一个没有使用的undo slot,然后记录对应的undo page的第一个页面的页号。当事务提交后,会优先重用undo page,但是复用是有条件的,要求链表中只有一个页面,如果是update类型的链表,写入的内容不超过75%。如果能复用,则将链表写入到每个回滚段的复用链表中,以便复用。事务提交后也要把undo slot中的数字改为fil_null。事务提交后,对于update的undo log需要将undo log写入到回滚段的history链表中,供mvcc使用。复用的逻辑是说创建undo page的时候优选冲复用链表中查找undo page页,而不是新创建。

7、什么是mvcc。
mvcc的全称是multi version concurrency control是用来解决读写冲突的,修改数据只能修改当前的值,如果在修改的时候,另一个线程来读,可以读取undo page。
mvcc里面需要涉及到transaction Id、roll pointer,这两个都是一条数据中隐藏的两个字段,前者是每个事务的id,是递增的,后者是指向的undo log的地址,undo log中还会有上一个undo log的地址,多个undo log组成了链表,叫做版本链。mvcc最核心的问题是如何根据事务的版本号来确定读取的undo page。
mvcc里面最核心的概念是read view,read view的概念需要涉及到如下几个概念
1、当前没有提交的事务id的集合,也就是活跃的事务id的集合;
2、活跃的事务id的集合中id最小的id,叫做min_id;
3、系统未下一个事务准备的事务id,叫做max_id;
在查询undo log的时候,先看数据上的事务id,如果事务id大于max_id,表示这个数据的产生是在本次行程read view后形成的,本次行程read view时该数据并不存在,是后发生的,及时它已经提交了也是读取不到的;如果是小于min_id,则肯定能读取到,因为已经提交了且是之前的事务做的修改,在min_id和max_id之间的要看是否是活跃的,如果是则读取不到,如果不是,则可以读取的到。
mvcc只在rc和rr中,在read uncommited隔离级别中,是没有mvcc的,因为此时直接读取最新的数据即可,不需要读取undo log。在RC和RR的时候才会有mvcc。只不过rc得时候,只要读取一次就会重新生成一次read view,所以如果一个事务上一次读取的时候没有提交,而本次读取的时候提交了,就会读取到,所以会有不可重复读的问题。而RR级别下,只会形成一个read view,所以不会有不可重复读的问题。在RR下再有mvcc的情况下,依然有幻读问题,幻读就是读取的数据和真实的数据不一致,比如某个sql查询了一下,然后另一个线程又更新了一些数据且符合了查询的sql,如果再次查询的话是查询不到的,也就是查询的数据和真实的数据发生了偏差;但是如果更新的话是可以更新到的,这就是幻读。解决幻读要使用加锁,强制读取当前而不是读取undo log。
上面说的只会在聚簇索引中才会发生,只有在聚簇索引中的数据才会有transaction id和roll pointer。

8、二级索引上不带有事务id,请问如何去查找原来的值?
当使用二级索引查询的时候,会检查二级索引的页上的一个属性,这个属性表示的是修改当前也的最大的事务id,如果这个最大的事务id小于mvcc中提到的min_trxid,则该页的所有的数据都是可读的,否则要回表。

9、undo log会一直写保存吗、什么时候删除?
undo log在修改数据的时候先记录,只要有数据更新就会写undo log,且也会用在数据恢复上,所以undo log需要做持久化。undo log的作用是留作给mvcc服务的,如果当前的read view产生的时间足够大,则不需要查看过早的历史数据,所以undo log不需要全部保留。innodb 里面除了trx_id以外,还会有一个叫做trx_no的东西,也是递增的,当事务提交的时候就会赋值给undo log,另外当形成一个read view的时候,会把当前系统重最大的trx_no+1复制给当前read view,假如当前trx_no最小的read view的trx_no是100,则trx_no小于100的事务的undo log都可以丢弃,因为小于100的事务都已经提交,且是更早就提交,只需要读取最新的数据即可。innodb有一个purge现成,它负责来删除,其中包括两部分,一部分是undo log的日志,还有一部分是做delete的数据。

10、mysql的删除是怎么删除的?
mysql的删除分为两步,一步是打标记,在每个行的记录中有一个部分是用来标记是否已删除的,这一步叫做delete mark。在每个叶子节点中,所有的数据分成两个链表,一个是正常的数据的链表,一个是做了删除之后的数据的链表。在做了delete mark后并不会立刻将数据写入到删除的链表,还是会在正常的链表中,真正加入到删除的链表也是purge线程做的,因为数据要留着做mvcc用,说不定有一个事务还要读取原来的数据呢。当purge发现trx_no最小的mvcc都大于做删除的事务的trx_no后就会真正的删除数据。

11、mysql崩溃恢复的原理
mysql在崩溃恢复的时候会优先用redo log做恢复,将数据恢复到没有崩溃之前的样子,然后再使用undo log做纠正,因为没有提交的事务的redo log也使用了。

12、mysql崩溃恢复的时候,没有提交的事务的redo log也重做了,不会有问题吗?
在崩溃恢复的时候,会查询回滚段中的undo slot,因为事务提交后会把undo slot设置为fil_null,如果一个事务没有提交,那么undo slot就是指向的undopage链表的第一个页面,根据这个来判断失误是否提交。如果不是fil_null,就能找到undo log的链表,然后做回滚,这样就保证了原子性。

13、innodb的锁类型,都包括什么
在RR隔离级别下:加锁的时候会检查where条件是否有索引,如果没有索引则加表锁;如果有唯一键索引,则加record lock,如果是普通索引,是record lock + gap lock,相当于是next key lock,因为有gap lock,不会再插入新的数据,所以不会有不可重复读的问题。
在RC隔离级别下:如果没有索引则加表锁,否则加record lock,因为没有gap lock,会插入新的数据,所以会有不可重复读的问题。

14、mysql在开启了binlog的时候,为什么要两阶段提交?
看这篇文章:https://cloud.tencent.com/developer/article/1965127

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值