Mysql
关于mysql的面试题都在这里了
面试官:什么是聚集索引?什么是非聚集索引?
聚集索引就是索引和数据都在同一个文件里,如InnoDB的xxx.idb文件,企业开发里,我似乎就没有用过非innodb的引擎,所以,我们日常开发中使用的基本都是聚集索引。也就是B+tree树。(这样是不是就很容易记住了)
那什么是非聚集索引?那当然是数据和索引不在同一个文件里了,类似MyISAM。
面试官:那B-tree 和 B+tree有什么区别?
(TMD,每次问这个有意思吗?)
B+tree叶子节点只存储索引,不存储数据,数据存储在最下一层的节点,并且是一个双向链表。
B-tree叶子节点即存储索索引又存储数据。
最底层是双向链表:每个节点都会记住头尾的指针,方便修改,新增,删除,支持范围查找。
面试官:那B+tree这样设计数据结构有什么好处?
B+tree只有在叶子结点上有数据,为了让IO每次读取的Page(16k)页更加多。
cpu 一次io读取16k,也就是一个非叶子结点,读取B+tree一次可以读取1170个非叶子结点的数据。
面试官:Innodb为什么必须有主键,而且用自增主键?而不是用UUID?
因为:
1:整型节省空间,一个节点存储更多的索引个数。
2.一个节点横向扫描比较大小很快。
3.why用自增,insert的时候直接加到最后,快,也不会再叶子结点出现分支。
面试官:InnoDB 事务工作原理
InnoDB 是一个事务性的存储引擎,而 InnoDB 的事务实现是基于事务日志 redo log 和 undo log 实现的
- 持久性:redo log 是重做日志,提供再写入操作,实现事务的持久性;
- 一致性:undo log 是回滚日志,提供回滚操作,保证事务的一致性。
面试官:那么Innodb支持哪些隔离级别?
- READ UNCOMMITTED (可以读未提交的): 查询可以读取到其他事务正在修改的数据,即使其他事务的修改还没有提交.这种隔离等级无法避免脏读.
- READ COMMITTED(只可以读已经提交的):其他事务对数据库的修改,只要已经提交,其修改的结果就是可见的,与这两个事务开始的先后顺序无关.这种隔离等级避免了脏读,但是无法实现可重复读,甚至有可能产生幻读.
- REPEATABLE READ(可重复读):比read committed更进了一步,它只能读取在它开始之前已经提交的事务对数据库的修改,在它开始以后,所有其他事务对数据库的修改对它来说均不可见.从而实现了可重复读,但是仍有可能幻
- SERIALIZABLE(可串行化):这是事务隔离等级的最高级别.其实现原理就是对于所有的query,即使是查询,也会加上读锁,避免其他事务对数据的修改.所以它成功的避免了幻读.但是代价是,数据库系统的并发处理能力大大降低,所以它不会被用到生产系统中.
那什么是幻想读? ?
“幻读”又叫"幻象读",是''不可重复读''的一种特殊场景:当事务1两次执行''SELECT ... WHERE''检索一定范围内数据的操作中间,事务2在这个表中创建了(如[[INSERT]])了一行新数据,这条新数据正好满足事务1的“WHERE”子句。如图事务1执行了两遍同样的查询语句,第二遍比第一遍多出了一条数据,这就是幻读。
有点烧脑....
面试官:如何解决幻读?
使用mvcc啊 !!!
在快照读读情况下,mysql通过mvcc来避免幻读。
在当前读读情况下,mysql通过next-key或者gap 锁来避免幻读。
MVCC就是,实现对数据库的并发访问用的技术。它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是,把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能。
实现原理:
innodb对每一行都加上了两个隐含的列,其中一列存储行被更新的”时间”,另外一列存储行被删除的”时间”. 但是innodb存储的并不是绝对的时间,而是与时间对应的数据库系统的版本号,每当一个事务开始的时候,innodb都会给这个事务分配一个递增的版本号,所以版本号也可以被认为是事务号.对于每一个”查询”语句,innodb都会把这个查询语句的版本号同这个查询语句遇到的行的版本号进行对比,然后结合不同的事务隔离等级,来决定是否返回该行.
在读取数据的时候,innodb几乎不用获得任何锁, 每个查询都通过版本检查,只获得自己需要的数据版本,从而大大提高了系统的并发度.
- SELECT时,读取创建版本号<=当前事务版本号,删除版本号为空或>当前事务版本号。
- INSERT时,保存当前事务版本号为行的创建版本号
- DELETE时,保存当前事务版本号为行的删除版本号
- UPDATE时,插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行
面试官:那你都知道mysql里的哪些锁,到底怎么用这些锁?
(说真的,开发中真的太少见用这些锁了,要不是为了面试,谁会复习这破玩意儿)
- 行锁:是加在索引行(对!是索引行!不是数据行!)上的锁。比如select * from user where id=1 and id=10 for update,就会在id=1和id=10的索引行上加Record Lock。
- Gap Locks 间隙锁,它会锁住两个索引之间的区域。比如select * from user where id>1 and id<10 for update,就会在id为(1,10)的索引区间上加Gap Lock。
- Next-Key Locks(间隙锁):也叫间隙锁,它是Record Lock + Gap Lock形成的一个闭区间锁。比如select * from user where id>=1 and id<=10 for update,就会在id为[1,10]的索引闭区间上加Next-Key Lock。这样组合起来就有,行级共享锁,表级共享锁,行级排它锁,表级排它锁。
- 读锁:保证数据只能读取,不能被修改。如果事务A对数据M加上S锁,则事务A可以读记录M但不能修改记录M,其他事务(这里用事务B)只能对记录M再加上S锁,不能加X锁,直到事务A释放了记录M上的S锁,保证了其他事务(事务B)可以读记录M,但在事务A释放M上的S锁之前不能对记录M进行任何修改。
- 写锁:若事务A对数据对象M加上X锁,事务A可以读记录M也可以修改记录M,其他事务(事务B)不能再对记录M加任何锁,直到事务A释放记录M上的锁,保证了其他事务(事务B)在事务A释放记录M上的锁之前不能再读取和修改记录M。
面试官:binlog用过吗?
binlog是Mysql sever层维护的一种二进制日志,与innodb引擎中的redo/undo log是完全不同的日志;其主要是用来记录对mysql数据更新或潜在发生更新的SQL语句,记录了所有的DDL和DML(除了数据查询语句)语句,并以事务的形式保存在磁盘中,还包含语句所执行的消耗的时间,MySQL的二进制日志是事务安全型的。
一般来说开启二进制日志大概会有1%的性能损耗(参见MySQL官方中文手册 5.1.24版)。
作用主要有:
- 复制:MySQL Replication在Master端开启binlog,Master把它的二进制日志传递给slaves并回放来达到master-slave数据一致的目的
- 数据恢复:通过mysqlbinlog工具恢复数据
- 增量备份
写再多可能就记不住了,抓住重点,这些足够应付大厂大头兵岗位了。如果你觉得有用給我点个赞吧。我是王炸,下期见!!