1.什么是聚集索引和非聚集索引
简单来说,聚集索引就是基于主键创建的索引,除了主键索引以外的其他索引,称为非聚集索引,也叫做二级索引。
- 由于在InnoDB引擎里面,一张表的数据对应的物理文件本身就是按照B+树来组织的一种索引结构,而聚集索引就是按照每张表的主键来构建一颗B+树,然后叶子节点里面存储了这个表的每一行数据记录。
- 所以基于InnoDB这样的特性,聚集索引并不仅仅是一种索引类型,还代表着一种数据的存储方式。
- 同时也意味着每个表里面必须要有一个主键,如果没有主键,InnoDB会默认选择或者添加一个隐藏列作为主键索引来存储这个表的数据行。一般情况是建议使用自增id作为主键,这样的话id本身具有连续性使得对应的数据也会按照顺序存储在磁盘上,写入性能和检索性能都很高。否则,如果使用uuid这种随机id,那么在频繁插入数据的时候,就会导致随机磁盘IO,从而导致性能较低。
- 需要注意的是,InnoDB里面只能存在一个聚集索引,原因很简单,如果存在多个聚集索引,那么意味着这个表里面的数据存在多个副本,造成磁盘空间的浪费,以及数据维护的困难。
- (如图)由于在InnoDB里面,主键索引表示的是一种数据存储结构,所以如果是基于非聚集索引来查询一条完整的记录,最终还是需要访问主键索引来检索。
2.请你简单说一下mysql的事务隔离级别
事务隔离级别,是为了解决多个并行事务竞争导致的数据安全问题的一种规范。
具体来说,多个事务竞争可能会产生三种不同的现象。
1.(如图)假设有两个事务T1/T2同时在执行,T1事务有可能会读取到T2事务未提交的数据,但是未提交的事务T2可能会回滚,也就导致了T1事务读取到最终不一定存在的数据产生脏读的现象。
2.(如图)假设有两个事务T1/T2同时执行,事务T1在不同的时刻读取同一行数据的时候结果可能不一样,从而导致不可重复读的问题。
3.(如图),假设有两个事务T1/T2同时执行,事务T1执行范围查询或者范围修改的过程中,事务T2插入了一条属于事务T1范围内的数据并且提交了,这时候在事务T1查询发现多出来了一条数据,或者在T1事务发现这条数据没有被修改,看起来像是产生了幻觉,这种现象称为幻读。
而这三种现象在实际应用中,可能有些场景不能接受某些现象的存在,所以在SQL标准中定义了四种隔离级别,分别是:
- 读未提交,在这种隔离级别下,可能会产生脏读、不可重复读、幻读。
- 读已提交(RC),在这种隔离级别下,可能会产生不可重复读和幻读。
- 可重复读(RR),在这种隔离级别下,可能会产生幻读
- 串行化,在这种隔离级别下,多个并行事务串行化执行,不会产生安全性问题。
这四种隔离级别里面,只有串行化解决了全部的问题,但也意味着这种隔离级别的性能是最低的。
3.MV***的理解
对于MV***的理解,我觉得可以先从数据库的三种并发场景说起:
第一种:读读
就是线程A与线程B同时在进行读操作,这种情况下不会出现任何并发问题。
第二种:读写
就是线程A与线程B在同一时刻分别进行读和写操作。
这种情况下,可能会对数据库中的数据造成以下问题:
- 事物隔离性问题,
- 出现脏读,幻读,不可重复读的问题
第三种:写写
就是线程A与线程B同时进行写操作
这种情况下可能会存在数据更新丢失的问题。
而MV***就是为了解决事务操作中并发安全性问题的无锁并发控制技术全称为Multi-Version Concurrency Control ,也就是多版本并发控制。它是通过数据库记录中的隐式字段,undo日志 ,Read View 来实现的。
MV***主要解决了三个问题
- 第一个是:通过MV*** 可以解决读写并发阻塞问题从而提升数据并发处理能力
- 第二个是:MV*** 采用了乐观锁的方式实现,降低了死锁的概率
- 第三个是:解决了一致性读的问题也就是事务启动时根据某个条件读取到的数据,直到事务结束时,再次执行相同条件,还是读到同一份数据,不会发生变化。
而我们在使用MV***时一般会根据业务场景来选择组合搭配乐观锁或悲观锁。
这两个组合中,MV***用来解决读写冲突,乐观锁或者悲观锁解决写写冲突从而最大程度的提高数据库并发性能。
4.日常工作中是怎么优化SQL
- 加索引,增加索引是一种简单高效的手段,但是需要选择合适的列,同时避免导致索引失效的操作,比如like、函数等。
- 避免返回不必要的数据列,减少返回的数据列可以增加查询的效率。
- 根据查询分析器适当优化SQL的结构,比如是否走全表扫描、避免子查询等
- 分库分表,在单表数据量较大或者并发连接数过高的情况下,通过这种方式可以有效提升查询效率
- 读写分离,针对读多写少的场景,这样可以保证写操作的数据库承受更小的压力,也可以缓解独占锁和共享锁的竞争。
5.Mysql为什么使用B+Tree作为索引结构
首先,常规的数据库存储引擎,一般都是采用B树或者B+树来实现索引的存储。
(如图)因为B树是一种多路平衡树,用这种存储结构来存储大量数据,它的整个高度会相比二叉树来说,会矮很多。
而对于数据库来说,所有的数据必然都是存储在磁盘上的,而磁盘IO的效率实际上是很低的,特别是在随机磁盘IO的情况下效率更低。
所以树的高度能够决定磁盘IO的次数,磁盘IO次数越少,对于性能的提升就越大,这也是为什么采用B树作为索引存储结构的原因。
(如图)但是在Mysql的InnoDB存储引擎里面,它用了一种增强的B树结构,也就是B+树来作为索引和数据的存储结构。
相比较于B树结构,B+树做了几个方面的优化。
- B+树的所有数据都存储在叶子节点,非叶子节点只存储索引。
- 叶子节点中的数据使用双向链表的方式进行关联。
使用B+树来实现索引的原因,我认为有几个方面。
- B+树非叶子节点不存储数据,所以每一层能够存储的索引数量会增加,意味着B+树在层高相同的情况下存储的数据量要比B树要多,使得磁盘IO次数更少。
- 在Mysql里面,范围查询是一个比较常用的操作,而B+树的所有存储在叶子节点的数据使用了双向链表来关联,所以在查询的时候只需查两个节点进行遍历就行,而B树需要获取所有节点,所以B+树在范围查询上效率更高。
- 在数据检索方面,由于所有的数据都存储在叶子节点,所以B+树的IO次数会更加稳定一些。
- 因为叶子节点存储所有数据,所以B+树的全局扫描能力更强一些,因为它只需要扫描叶子节点。但是B树需要遍历整个树。
另外,基于B+树这样一种结构,如果采用自增的整型数据作为主键,还能更好的避免增加数据的时候,带来叶子节点分裂导致的大量运算的问题。
总结:
技术方案的选型,更多的是去解决当前场景下的特定问题,并不一定是说B+树就是最好的选择,就像MongoDB里面采用B树结构,本质上来说,其实是关系型数据库和非关系型数据库的差异。
6.Mysql索引的优点和缺点?
索引,是一种能够帮助Mysql高效从磁盘上检索数据的一种数据结构。
在Mysql中的InnoDB引擎中,采用了B+树的结构来实现索引和数据的存储
Mysql里面的索引的优点有很多
- 通过B+树的结构来存储数据,可以大大减少数据检索时的磁盘IO次数,从而提升数据查询的性能
- B+树索引在进行范围查找的时候,只需要找到起始节点,然后基于叶子节点的链表结构往下读取即可,查询效率较高。
- 通过唯一索引约束,可以保证数据表中每一行数据的唯一性
当然,索引的不合理使用,也会有带来很多的缺点。
- 数据的增加、修改、删除,需要涉及到索引的维护,当数据量较大的情况下,索引的维护会带来较大的性能开销。
- 一个表中允许存在一个聚簇索引和多个非聚簇索引,但是索引数不能创建太多,否则造成的索引维护成本过高。
- 创建索引的时候,需要考虑到索引字段值的分散性,如果字段的重复数据过多,创建索引反而会带来性能降低。
7.索引什么时候失效?
1.在索引列上做运算,比如使用函数,Mysql在生成执行计划的时候,它是根据统计信息来判断是否要使用索引的。
而在索引列上加函数运算,导致Mysql无法识别索引列,也就不会再走索引了。
不过从Mysql8开始,增加了函数索引可以解决这个问题。
2.在一个由多列构成的组合索引中,需要按照最左匹配法则,也就是从索引的最左列开始顺序检索,否则不会走索引。
在组合索引中,索引的存储结构是按照索引列的顺序来存储的,因此在sql中也需要按照这个顺序才能进行逐一匹配。
否则InnoDB无法识别索引导致索引失效。
3.当索引列存在隐式转化的时候, 比如索引列是字符串类型,但是在sql查询中没有使用引号。
那么Mysql会自动进行类型转化,从而导致索引失效
4.在索引列使用不等于号、not查询的时候,由于索引数据的检索效率非常低,因此Mysql引擎会判断不走索引。
5.使用like通配符匹配后缀%xxx的时候,由于这种方式不符合索引的最左匹配原则,所以也不会走索引。
但是反过来,如果通配符匹配的是前缀xxx%,符合最左匹配,也会走索引。
6.使用or连接查询的时候,or语句前后没有同时使用索引,那么索引会失效。只有or左右查询字段都是索引列的时候,才会生效。
除了这些场景以外,对于多表连接查询的场景中,连接顺序也会影响索引的使用。
不过最终是否走索引,我们可以使用explain命令来查看sql的执行计划,然后针对性的进行调优即可。
8. InnoDB 与MyISAM 有什么区别
- 事务支持不同,InnoDB 支持事务处理,而 MyISAM 不支持。
- 并发处理不同:InnoDB 支持行级锁,而 MyISAM 支持表级锁
- 外键支持不同:InnoDB 支持外键约束,而 MyISAM 不支持
- 性能上存在差异:MyISAM 的读取速度比 InnoDB 快,但是在高并发环境下,InnoDB 的性能更好。这是因为 InnoDB 支持行级锁和事务处理,而 MyISAM 不支持。
所以,如果是读多写少的情况下,使用MyISAM引擎会更合适
5.数据安全不同:InnoDB 支持崩溃恢复和数据恢复,而 MyISAM 不支持。如果 MySQL 崩溃了或者发生意外故障,InnoDB 可以通过恢复日志来恢复数据。
9.为什么 SQL 语句不要过多的 join?
- 性能问题:每个 join 操作都需要对两个或多个表进行连接操作,这个操作需要消耗大量的计算资源和时间,如果 join 操作过多,会导致 SQL 的执行效率降低,从而影响整个系统的性能。
- 可读性和维护性问题:join 操作会使 SQL 语句变得复杂,难以理解和维护,特别是当 join 操作涉及到多个表的时候,SQL 语句的复杂度会呈现指数级增长,给代码的可读性和可维护性带来挑战。
10.binlog和redolog有什么区别?
binlog和redolog都是Mysql里面用来记录数据库数据变更操作的日志。
{如图}其中binlog主要用来做数据备份、数据恢复和数据同步,大家初步接触这个概念 ,应该是在Mysql的主从数据同步的场景中,master节点的数据变更,会写入到binlog中,然后再把binlog中的数据通过网络传输给slave节点,实现数据同步。
问题答案
binlog和redolog的区别有很多,我可以简单总结三个点
- 使用场景不同,binlog主要用来做数据备份、数据恢复、以及主从集群的数据同步; Redo Log主要用来实现Mysql数据库的事务恢复,保证事务的ACID特性。当数据库出现崩溃的时候,Redo Log可以把未提交的事务回滚,把已提交的事务进行持久化,从而保证数据的一致性和持久性。
- 记录的信息不同,binlog是记录数据库的逻辑变化,它提供了三种日志格式分别是statement,row以及mixed;
redo log记录的是物理变化,也就是数据页的变化结果。
- 记录的时机不同, binlog是在执行SQL语句的时候,在主线程中生成逻辑变化写入到磁盘中,所以它是语句级别的记录方式; RedoLog是在InnoDB存储引擎层面的操作,它是在Mysql后台线程中生成并写入到磁盘中的,所以它是事务级别的记录方式,一个事务操作完成以后才会被写入到redo log中。
粉丝福利(非常重要!!)
最新2023整理收集的一些高频面试题(都整理成一个文档),有很多干货,包含mysql,***ty,spring,线程,spring cloud、jvm、源码、算法等详细讲解(大概50w字左右),也有详细的学习规划图,面试题整理等,需要获取这些内容的朋友点赞+关注后私信回复《578》即可免费获取!