MySQL& innoDB

MySQL & innoDB

1.为什么生产环境中B+树的高度总是3-4层?

答案:一个高度为 3 的 B+ 树大概可以存放 1170 × 1170 × 16 = 21902400 行数据,已经是千万级别的数据量了,前提是每条数据只有1KB大小
解释:
在计算机中磁盘存储数据最小单元是扇区,一个扇区的大小是 512 字节,而文件系统的最小单元是块,一个块的大小是 4k,而对于我们的 InnoDB 存储引擎也有自己的最小储存单元——页(Page),一个页的大小是 16K
那么,InnoDB的一页,可以存放多少条数据呢?假设一条数据大小1KB,那么一个InnoDB的页可以存放16条数据;
Mysql中⼀个 Innodb⻚就是⼀个B+树节点
假设主键 ID 为 bigint 类型,占8字节,而指针大小在 InnoDB 源码中设置为 6 字节,这样一共 14 字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即 16384/14=1170。
一个高为3的B+树,其第一层,只能存放1170个指针;其前两层,可以存放11701170个指针;前两层有11701170个指针,可以指向1170*1170个dataNode,一个dataNode能放16条数据,所以这一棵树能存放1170 × 1170 × 16 = 21902400条数据,即2千多万条。

2.为什么要使用自增ID作为主键?

对InnoDB来说,主键索引是聚簇索引,既存储索引值,又在叶子节点中存储行的数据。如果主键自增,那么每次插入一条数据都会在当前索引的后续位置,当这一页达到装载因子时,InnoDB会开启新的一页。而如果主键非自增,无规律可循,那可以认为它是随机的,这样一来,完全随机的插入数据会导致大量的B+树分裂旋转,以及产生大量的空间碎片,浪费空间。

3.为什么使用数据索引能提高效率?

数据索引的存储是有序的。有序的数据结构的查找,可以用到二分的思想,其时间复杂度趋近于 log2(N)。

4.B+树索引和哈希索引的区别?

1.其底层依赖的数据结构不同,B+树索引是多叉平衡树,根据索引值的大小进行有序的存储;哈希索引是类似于哈希表的结构,其值的存放是无序的;
2.对于单个值的查询,哈希索引的复杂度为O(1);而B+树的时间复杂度为log(2)(m)*log(m)(n) = log(2)(n),用到了对数的换底公式;
3.哈希索引不支持范围查询;
4.哈希索引适用于大量等值查询的情况,而B+树索引适用于大多数情况。

5.B+树与B树的区别?

B树的每个节点存储了key和data。而B+树改进了B树, 让非叶子节点只存放key, 去掉了其中指向data的指针, 使得每个结点中能够存放更多的key, 因此能有更大的出度. 这样就意味着B+树的层高能进一步被压缩, 使得检索的时间更短。
由于底部的叶子结点是链表形式, 因此也可以实现更方便的顺序遍历。

6.MySQL的联合索引?

联合索引是两个或更多个列上的索引。
假设有一个联合索引index(a,b,c),在索引建立的时候,是按照“如果a不相等,就按照a排序;否则,如果b不相等,就按照b排序,否则,就按照c排序”,因此,建立好的索引在全局上看,只有a是有序的,而b和c在全局上看都是无序的,只有a相同的时候,b才有序;a,b都有序的时候,c才有序。
注意:

下面几个会走索引
select * from test where a = ‘333’ and b = ‘333’ and c = ‘333’;
select * from test where b = ‘333’ and a = ‘333’ and c = ‘333’;
select * from test where c = ‘333’ and b = ‘333’ and a = ‘333’;
select * from test where a = ‘333’ and c = ‘333’;

而不遵循最左前缀原则的,就不会走索引。如:

select * from test where b = ‘333’ and c = ‘333’;

7.数据库的几大范式?

第一范式
第一范式比较简单,属性不可拆分。电话号码一个字段可以分为手机号码和座机号码两个字段。
第二范式
第二范式不难理解,非主属性对主键完全依赖,不能存在部分依赖(比如联合主健)。候选键只有一个主属性时则一定符合第二范式。
第三范式 3NF
属于第二范式,要求任何非主键都没有传递依赖
BC范式
BC范式则不应存在关键字决定关键字的情况。也就是在关联关系表中,一个表有多个属性构成复合的候选键,主属性直接不应该有互相依赖。工号和身份证号是相互依赖。
第四范式
已经是BC范式,并且最多只能有一个多值属性依赖。
在这里插入图片描述

8.索引的类型有哪些?

从索引的定义来看:主键索引,唯一索引,普通索引,全文索引(MySQL的全文索引不支持中文)。
从实现来看:
FULLTEXT,HASH,BTREE,RTREE
FULLTEXT全文索引主要是用来解决WHERE name LIKE "%zhang%"等针对文本的模糊查询效率低的问题。多在CHAR,VARCHAR,TAXT等数据类型上创建全文索引。

9.聚簇索引(主键索引)和非聚簇索引(辅助索引)?

聚簇索引(主键索引):将数据和索引放到一起存储,索引结构的叶子节点保留了数据行。主键上建立的索引就是聚簇索引。
非聚簇索引(辅助索引):将数据进和索引分开存储,索引叶子节点存储的主键的值。非主键建立的索引就是非聚簇索引。
通过辅助索引来查询的时候,先查询到对应的主键值,再拿到主键索引,去主键索引查找行数据。

优点:
1.数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快
2.聚簇索引对于主键的排序查找和范围查找速度非常快
缺点:
1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键
2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。

10.非聚簇索引一定会进行回表查询吗?

上面是说了非聚簇索引的叶子节点存储的是主键,也就是说要先通过非聚簇索引找到主键,再通过聚簇索引找到主键所对应的数据,后面这个再通过聚簇索引找到主键对应的数据的过程就是回表查询,那么非聚簇索引就一定会进行回表查询吗?
答案是不一定的,这里涉及到一个索引覆盖的问题,如果查询的数据在辅助索引上完全能获取到便不需要回表查询。

11.索引的使用场景有哪些?建立索引就一定快吗?

对于中大型表建立索引非常有效,对于非常小的表,一般全部表扫描速度更快些。
如何表的增删改非常多,而查询需求非常少的话,那就没有必要建立索引了,因为维护索引也是需要代价的。
一般不会出现在where条件中的字段就没有必要建立索引了。
多个字段经常被查询的话可以考虑联合索引。

12.什么是前缀索引?

前缀索引是指对文本或者字符串的前几个字符建立索引,这样索引的长度更短,查询速度更快。

13.什么是数据库的事务?

数据库事务( transaction)一个数据库操作序列,这些操作要么全部执行,要么全部不执行,不可分割。

14.数据库的并发一致性问题?

脏读:事务A更新了数据,但还没有提交,这时事务B读取到事务A更新后的数据,然后事务A回滚了,事务B读取到的数据就成为脏数据了。
不可重复读:事务A对数据进行多次读取,事务B在事务A多次读取的过程中执行了更新操作并提交了,导致事务A多次读取到的数据并不一致。
幻读:事务A在读取数据后,事务B向事务A读取的数据中插入了几条数据,事务A再次读取数据时发现多了几条数据,和之前读取的数据不一致。
丢失更新:事务A和事务B都对同一个数据进行修改,事务A先修改,事务B随后修改,事务B的修改覆盖了事务A的修改。

15.数据库的隔离级别有哪些?

读未提交:一个事务在提交前,它的修改对其他事务也是可见的。
读已提交:一个事务提交之后,它的修改才能被其他事务看到。
可重复读:在同一个事务中多次读取到的数据是一致的。
串行化:需要加锁实现,会强制事务串行执行。

数据库的隔离级别分别可以解决数据库的脏读、不可重复读、幻读等问题。
在这里插入图片描述

16.隔离级别是如何实现的?

事务的隔离机制主要是依靠锁机制和MVCC(多版本并发控制)实现的,提交读和可重复读可以通过MVCC实现,串行化可以通过锁机制实现。

17.什么是MVCC?MVCC如何实现读已提交/可重复度?

MVCC(multiple version concurrent control)是一种控制并发的方法,主要用来提高数据库的并发性能。
首先,要知道版本链
在InnoDB中,数据表中的每一行除了本身的数据字段之外,还包含有两个隐藏的字段:

trx_id
这个id用来存储的每次对某条引记录进行修改的时候的事务id。
roll_pointer
每次对哪条引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性,因为它没有老版本)
在这里插入图片描述

其次要知道ReadView
ReadView中主要就是有个列表来存储我们系统中当前活跃着的读写事务,也就是begin了还未提交的事务。

下面举例说明MVCC如何实现读已提交和可重复读:
假设当前列表里的事务id为[8,9,10]。
来了一个事务id为11的事务,他要做一次查询,那么他就只能读事务id比自己小,且没有出现在活跃列表里面的记录。
然后,8提交了。
在读已提交的隔离级别下,会生成[9, 10]这样的活跃列表;
而在可重复读的隔离级别下,会生成[8, 9, 10]这样的活跃列表。

总结一句就是,读已提交隔离级别下的事务在每次查询的开始都会生成一个独立的活跃列表, 而可重复读隔离级别则在第一次读的时候生成一个活跃列表,之后的读都复用之前的活跃列表。

点击查看
结论

MVCC下,select是快照读,其他的都是当前读,还有就是如果对select加了锁,那么select也是当前读
select k from t where id=1 lock in share mode;

在这里插入图片描述
事务C’没提交,也就是说(1,2)这个版本上的写锁还没释放。而事务B是当前读,必须要读最新版本,而且必须加锁,因此就被锁住了,必须等到事务C’释放这个锁,才能继续它的当前读。
在这里插入图片描述
可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。

18.MySql分表和分区?

分区:

表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。

分表:

指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。

分表与分区的区别在于:

分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。

表分区有什么好处?

1、存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据
2、优化查询。在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。

最常见的分区操作是RANGE分区,根据分区键的大小划分成若干个范围,每个范围成为一个分区;
还有其他的分区操作:list分区、hash分区、key分区

19. redo log, undo log, bin log

redo log

概念

redo log通常是物理日志,是innodb的日志,记录的是事务对数据页的物理修改(比方说某个事务将系统表空间中的第100号页面中偏移量为1000处的那个字节的值1改成了2,那么我们在redo log中记录 : 表空间的100号页面的偏移量为1000处的值更新为2),而不是某一行或某几行修改成怎样怎样。

什么时候产生
在这里插入图片描述
在这里插入图片描述

数据页到内存中–>修改数据–>更新数据页–>写入redolog,状态为prepare–>写binlog–>提交事务,redolog状态修改为commit

事务开始之后就产生redo log,先写入redo log buffer,再通过以下几种机制将buffer中的log刷到磁盘:
在这里插入图片描述

1.Master Thread 每秒一次执行刷新Innodb_log_buffer到重做日志文件。
2.每个事务提交时会将重做日志刷新到重做日志文件。
3.当重做日志缓存可用空间 少于一半时,重做日志缓存被刷新到重做日志文件
即使某个事务还没有提交,Innodb存储引擎仍然每秒会将重做日志缓存刷新到重做日志文件。

什么时候释放:

对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。

作用

1.保证了事务的持久性。
2.数据库崩溃时回复。如:A字段本来=1,设置A字段=5,内存中的数据data buffer已经改了,redo log也刷入磁盘中了,事务也提交了,但是还没来及的把A字段=5刷到磁盘中,数据库就挂了,那再恢复了数据库看到的A字段就是=1,这时就用redo log来回放把A变成=5

undo log一般是逻辑日志,根据每行记录进行记录。undo用来回滚行记录到某个版本。

bin log

二进制日志,他记录了MySQL所有数据的变更,并以二进制的形式存储在磁盘上。
binlog有三种模式:ROW(行模式), Statement(语句模式), Mixed(混合模式)

ROW(行模式):记录那条数据修改了,注意:记录的是这条记录的全部数据,即使只更新了一个字段,binlog里也会记录所有字段的数据
优点:他不记录sql语句的上下文信息,日志内容会非常清楚的记录每条数据详细的变更细节,即使只更新了一个字段,binlog里也会记录所有字段的数据。
缺点:binlog日志会非常大,mysql主从同步时,会产生大量磁盘IO
Statement(语句模式): 每一条会修改数据的sql都会记录在binlog中。
优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题。
Mixed(混合模式):在Mixed模式下,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。

作用

主从复制(Replication)和故障恢复(Recovery)

undo log

记录了数据库中记录的多个版本,以链的形式将新旧版本串联起来。用于事务回滚,MVCC

20.WAL Write Ahead Log

WAL机制是通过用一个更快的方式记录更新数据(写redo log),然后等系统空闲的时候,再把redo log的更新数据写回到mysql磁盘数据中。
有人会问:redo log 日志也是存在于磁盘中啊,既然日志是存在磁盘中,mysql数据也是存在磁盘中,都是要写磁盘啊,那还搞那么多干嘛
区别就是,redo log是顺序写盘的,速度很快,redo log的写方式是顺序IO,更新磁盘操作是随机IO,随机IO和顺序IO相比,有一个寻址的过程,所以顺序写盘更快。

21.事务的ACID

原子性

原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。

一致性

事务必须使数据库从一个一致性状态变换到另外一个一致性状态。即数据库从当前状态,经过事务,转换到另一个预期的状态。

隔离性

多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰

持久性

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的

22.为什么可重复读的隔离级别还会出现幻读

在这里插入图片描述
可重复读不能防止“写的幻读”。因为select走的是“快照读”,而update,delete,insert走的都是“当前读”。

23.MySQL的锁

全局锁

对整个数据库实例加锁,会让整个库处于只读状态,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
全局锁的典型使用场景是,做全库逻辑备份。

表锁
有两种:普通表锁,还有就是MDL(metadata lock)锁,后者在事务开启的时候会自动申请锁,在事务结束时会自动释放锁。在对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作(DDL)的时候,加MDL写锁。读锁之间不互斥。

开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低。
需要注意,lock tables语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
举个例子, 如果在某个线程A中执行lock tables t1 read, t2 write; 这个语句,则其他线程写t1、读写t2的语句都会被阻塞。同时,线程A在执行unlock tables之前,也只能执行读t1、读写t2的操作。连写t1都不允许,自然也不能访问其他表。

行锁
innodb中,RR隔离级别下,行锁会默认的加。比如一个事务中,update某一行,然后在事务没有结束之前,这一行其他事务是无法修改的,但是可以读。
在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议
行锁可能会死锁:
在这里插入图片描述
当出现死锁以后,有两种策略

一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置。(业务有损,用户体验差
另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。(业务无损,但是耗费cpu资源
办法就是:尽量避免出现行的死锁
一方面可以考虑限制客户端的并发数
另一方面可以考虑通过将一行改成逻辑上的多行来减少锁冲突。还是以影院账户为例,可以考虑放在多条记录上,比如10个记录,影院的账户总额等于这10个记录的值的总和。这样每次要给影院账户加金额的时候,随机选其中一条记录来加。这样每次冲突概率变成原来的1/10,可以减少锁等待个数,也就减少了死锁检测的CPU消耗。

开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低。
InnoDB行锁和表锁都支持、MyISAM只支持表锁!
InnoDB只有通过索引条件检索数据才使用行级锁,否则,InnoDB使用表锁也就是说,InnoDB的行锁是基于索引的!

间隙锁
select * from table where pk > value for update
给pk > value的范围加上间隙锁
RR级别下,间隙锁也会默认的加

间隙锁一定是开区间,比如(3,5)。间隙锁不是互斥的,正是因为它不互斥,所以可能会导致死锁,如下案例:
如果一个事务A获取到了(5,10]之间的间隙锁且不允许其他的DDL操作,在事务提交,间隙锁释放之前,事务B也获取到了间隙锁(5,10],这时两个事务就处于死锁状态。

next-key锁

行锁和间隙锁组合起来就叫Next-Key Lock。

共享锁/排他锁

共享锁/排他锁都只是行锁

24.MyISAM 和 InnoDB 比较

1.MyISAM不支持事务,而InnoDB支持。InnoDB每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速度,所以最好是把多条SQL语句显示放在begin和commit之间,组成一个事务去提交。
2.InnoDB支持数据行锁定,MyISAM不支持行锁定,只支持锁定整个表。MyISAM同一个表上的读锁和写锁是互斥的,MyISAM并发读写时如果等待队列中既有读请求又有写请求,默认写请求的优先级高,即使读请求先到,所以MyISAM不适合于有大量查询和修改并存的情况,那样查询进程会长时间阻塞。因为MyISAM是锁表,所以某项读操作比较耗时会使其他写进程饿死。
3.InnoDB支持外键,MyISAM不支持。
4.myisam允许没有任何索引和主键的表存在,innodb引擎如果没有设定主键,就会自动生成一个6字节的主键(用户不可见)
5.myisam保存有表的总行数,如果select count() from table;会直接取出出该值。innodb没有保存表的总行数,如果使用select count() from table;就会遍历整个表,消耗相当大。但是加了where的count,两者效率差不多。
6.数据库文件不同:myisam中,.MYD后缀 用于存放数据,.MYI后缀 用于存放表索引;而innoDB中索引和数据一起存放

点击查看

25.为什么用b+树而不用红黑树、b树?

b+树和B树都是多叉树,区别在于,b+树的非叶子节点不存放数据,只放索引;而B树的节点既有索引又有数据;而innoDB默认页大小是16KB,一般来说一个页面存放一个树节点,所以同样大小的树节点,b+树可以存放更多的索引信息,从而b+树的高度通常会比B树的高度低得多。
红黑树是二叉树,b+树是多叉树,同样索引条数,红黑树更高。
树的高度和IO次数直接挂钩,而IO又是很慢的,所以为了效率,innoDB选择了B+树。

26.索引的创建以及删除的SQL语句

CREATE INDEX indexName ON mytable(username(length));
DROP INDEX [indexName] ON mytable;

27.如何优化SQL语句?

点击查看

28.一条SQL语句的执行过程?

点击查看
查询:
1.先要连接到MySQL,由 连接器 对连接进行验证;
2.连接成功后,去 查询缓存 看是否有缓存, 查询缓存很容易失效,在MySQL8之后就被移除了;
如果没有命中缓存,就要准备执行这条语句;否则直接返回;
3.进行语法解析和预处理:
分词:将sql语句分词;
语法分析:对sql语句进行语法检查;
预处理:检查表名/字段名是否存在;
期间如果有错,直接返回。
4.优化器:
一条SQL语句有多个执行计划,选择一种它认为最优的执行计划去执行。
5.执行器:
拿着 执行计划 去对应的存储引擎 去执行, 返回结果。

更新:
1.先要连接到MySQL,由 连接器 对连接进行验证;
2.让对应表的缓存失效;
3.分析器对语句进行分析,如果有语法错误直接报错;
4.经过分析器,发现是update,于是要先去select,由优化器决定选择哪个执行计划;
5.执行器执行之后,返回要修改的行;
6.在内存中,对改行进行修改;
7.redo log记录更新,并且将该修改记录为prepare状态;
8.binlog记录更新;
9.redo log将prepare改为commit,表示更新完成。

29.谈谈MySQL的EXPLAIN

点击查看
对EXTRA字段的解释

30.一条SQL查询语句是如何执行的

MySQL由sever层+存储引擎层组成。Server层包括连接器、查询缓存、分析器、优化器、执行器等,而存储引擎层负责数据的存储和提取。
在这里插入图片描述

第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接。
在这里插入图片描述show processlist命令可以看到连接的情况。客户端如果太长时间没动静,连接器就会自动将它断开。默认时间是8小时。
连接建立完成后,你就可以执行select语句了。执行逻辑就会来到第二步:查询缓存(在MySQL8.0之后就没有这个功能了)。
之前执行过的语句及其结果可能会以key-value对的形式,被直接缓存在内存中。key是查询的语句,value是查询的结果。但是,查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。
第三步:分析器
如果没有命中查询缓存,就要开始真正执行语句了。分析器主要对SQL语句做解析,如果发现SQL语句有语法错误,直接报错;否则进入下一步:
第四步:优化器
优化器主要是对要执行的SQL语句做优化处理,比如在表里面有多个索引的时候,决定使用哪个索引,优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。
第五步:执行器
MySQL通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。
先判断当前用户有无权限做对应的操作;
打开对应的表,执行操作,返回结果。

31.redolog的二阶段提交

在这里插入图片描述
如果不二阶段提交,那么写这两个log文件必然有一个先后顺序:
1.先写redolog:写完redolog后crash,这时候机器重启,要根据redolog来恢复数据,此时的redolog中要比binlog多一些数据,所以根据redolog恢复出的数据库,与后续通过binlog来恢复数据库不一样,会丢失一部分操作;
2.先写binlog:写完binlog后crash,这时候机器重启,根据redolog来恢复数据,redolog要比binlog少一些数据,所以根据redolog恢复出的数据库,与后续通过binlog来恢复数据库不一样,会丢失一部分操作;

对于redulog的两阶段提交:
假设在写入binlog前系统崩溃,那么数据库恢复后顺序扫描 redo log,碰到只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务,而且binlog也没写入,所以事务就直接回滚了。
假设redolog中有一部分已经打上了commit标记,说明binlog已经写完整了,则完整恢复数据。

32.既然已经有redolog了,那是否可以抛弃binlog?

不可以,一是因为redolog只有innodb有;二是因为redolog是循环覆盖的写,保存不了太多数据,全量归档还是得靠binlog。
镜像问题:只用binlog,不用redo log,是否能做到crash恢复?
不可以,因为只用binlog,并不知道binlog中记录的哪些数据是脏数据,所以不知道从哪儿开始恢复。而redolog的作用就是:redolog中记录的,都是待刷盘的数据,即脏数据,让数据库在crash重启之后可以知道从哪儿开始刷盘。

33.MySQL如何支持事务 ?undo log如何保证原子性 ?

点击查看

34.B+树的插入过程?画图演示

点击查看
例子:一个3阶B+树的插入过程.
插入都是在叶子节点进行插入
下图是叶子节点的节点数少于m
在这里插入图片描述
下图是叶子节点的节点数等于m,需要将该结点分裂为两个结点,一个结点包含 ⌊M/2⌋ ,另一个结点包含 ⌈M/2⌉:
在这里插入图片描述

35.MySQL有哪些类型的索引?索引覆盖?

点击查看
主要从逻辑角度,数据结构角度,物理存储角度出发。

索引覆盖
索引覆盖的优化场景:
1.全表count查询优化
2.列查询回表优化

36.为什么like %xxx不走索引?

点击查看

37.change buffer

总结:在非唯一普通索引(之所以不支持唯一索引,是因为唯一索引每次写,都要检查索引的唯一性,所以必须进行IO操作,没有优化空间)上,进行change操作,并且要操作的数据页并不在缓存池中,这时候为了加快写的速度,并不会立即将对应的数据页读到缓冲池中,而是先将change操作写到change buffer中,同时记录redo log,这样就加快了change操作的速度。
那change操作什么时候才真正的修改磁盘上的数据页呢?就是当读操作发生在对应的页时,要将之前缓存的change操作merge到页里面,写入缓冲池;如果长时间没有读操作发生,那么change buffer会写入磁盘,或者定期进行merge,在数据库正常关闭(shutdown)的过程中,也会执行merge操作。
在这里插入图片描述

点击查看

38.MySQL删除记录时,是真正的把记录从磁盘上删除了吗?

并没有,删除记录,只是将记录所在的的磁盘空间标记为可复用,后续如果有满足条件的数据插入,可直接复用这块区域。如果一个数据页上的数据全被删除了,那么这一整块数据页都是可复用的,而且不需要满足任何条件,就可以写入数据;如果一个表的全部数据都被删除了,那么这个表对应的所有数据页都可复用。
innodb的数据表由两部分组成,表结构和表数据,所以在删除的时候,表数据文件的大小是不变的。
更新索引上的值,可以理解为删除一个旧的值,再插入一个新值。
大量的随机插入会导致页分裂,空间利用率降低,写入效率也会变低(随机写入)。为了解决这一问题,可以将索引设置为自增,或者重建表(试想一下,如果你现在有一个表A,需要做空间收缩,为了把表中存在的空洞去掉,你可以怎么做呢?你可以新建一个与表A结构相同的表B,然后按照主键ID递增的顺序,把数据一行一行地从表A里读出来再插入到表B中。)

39.什么是online DDL?

DDL(Data Definition Language):用来操作数据库、数据表、视图这些对象。
一般来说,DDL都是离线的,因为一般DDL和数据表的增删改不能同时进行。
MySQL 5.6版本开始引入的Online DDL,对这个操作流程做了优化。
重建表为例子,简单描述一下引入了Online DDL之后,重建表的流程:

建立一个临时文件,扫描表A主键的所有数据页;
用数据页中表A的记录生成B+树,存储到临时文件中;
生成临时文件的过程中,将所有对A的操作记录在一个日志文件(row log)中,对应的是图中state2的状态;
临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表A相同的数据文件,对应的就是图中state3的状态;
用临时文件替换表A的数据文件。
在这里插入图片描述

40.为什么InnoDB不跟MyISAM一样,也把count(*)的数字存起来呢?

由于多版本并发控制(MVCC)的原因,InnoDB表“应该返回多少行”也是不确定的,每一行记录都要判断自己是否对这个会话可见,因此对于count(*)请求来说,InnoDB只好把数据一行一行地读出依次判断。

41.index merge(索引合并)?

点击查看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值