mysql 面试必看

列式存储和行式存储适应场景

⾏式存储是把⼀⾏的数据都串起来进⾏存储,然后再存储下⼀⾏。同样,列式存储是把⼀列的数据都串起来进⾏存储,然后再存储下⼀列。这样做的话,相邻数据的数据类型都是⼀样的,更容易压缩,压缩之后就⾃然降低了I/O。

数据处理可以分为OLTP(联机事务处理)和OLAP(联机分析处理)两⼤类。

OLTP⼀般⽤于处理客⼾的事务和进⾏查询,需要随时对数据表中的记录进⾏增删改查,对实时性要求⾼。

OLAP⼀般⽤于市场的数据分析,通常数据量⼤,需要进⾏复杂的分析操作,可以对⼤量历史数据进⾏汇总和分析,对实时性要求不⾼。

那么对于OLTP来说,由于随时需要对数据记录进⾏增删改查,更适合采⽤⾏式存储,因为⼀⾏数据的写⼊会同时修改多个列。传统的RDBMS都属于⾏式存储,⽐如Oracle、SQL Server和MySQL等。对于OLAP来说,

由于需要对⼤量历史数据进⾏汇总和分析,则适合采⽤列式存储,这样的话汇总数据会⾮常快,但是对于插⼊(INSERT)和更新(UPDATE)会⽐较⿇烦,相⽐于⾏式存储性能会差不少。所以说列式存储适合⼤批量数据查询,可以降低I/O,但如果对实时性要求⾼,则更适合⾏式存储。

一条sql 的完整执行顺序

  1. FROM⼦句组装数据(包括通过ON进⾏连接);
  2. WHERE⼦句进⾏条件筛选;
  3. GROUP BY分组 ;
  4. 使⽤聚集函数进⾏计算;
  5. HAVING筛选分组;
  6. 计算所有的表达式;
  7. SELECT 的字段;
  8. ORDER BY排序;
  9. LIMIT筛选。

count(*)、count(1)、count(字段) 执行效率

  1. ⼀般情况下,三者执⾏的效率为 COUNT()= COUNT(1)> COUNT(字段)。我们尽量使⽤COUNT(),当然如果你要统计的是某个字段的⾮空数据⾏数,则另当别论,毕竟⽐较执⾏效率的前提是结果⼀样才可以。
  2. 如果要统计COUNT(),尽量在数据表上建⽴⼆级索引,系统会⾃动采⽤key_len⼩的⼆级索引进⾏扫描,这样当我们使⽤SELECT COUNT()的时候效率就会提升,有时候可以提升⼏倍甚⾄更⾼。

数据表的三范式指的是什么?

  1. 1NF指的是数据库表中的任何属性都是原⼦性的,不可再分 。
  2. 2NF指的数据表⾥的⾮主属性都要和这个数据表的候选键有完全依赖关系 。
  3. 3NF在满⾜2NF的同时,对任何⾮主属性都不传递依赖于候选键 。

事务四大特性

事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。

  1. 原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
  2. 一致性(Consistent) :⼀致性指的就是数据库在进⾏事务操作后,会由原来的⼀致状态,变成另⼀种⼀致的状态。也就是说当事务提交后,或者当事务发⽣回滚后,数据库的完整性约束不能被破坏。
  3. 隔离性(Isolation) :它指的是每个事务都是彼此独⽴的,不会受到其他事务的执⾏影响。也就是说⼀个事务在提交之前,对其他事务都是不可⻅的。
  4. 持久性(Durable) :事务提交之后对数据的修改是持久性的,即使在系统出故障的情况下,⽐如系统崩溃或者存储介质发⽣故障,数据的修改依然是有效的。因为当事务完成,数据库的⽇志就会被更新,这时可以通过⽇志,让系统恢复到最后⼀次成功的更新状态。

并发事务处理带来的问题

更新丢失(Lost Update)

当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。

脏读(Dirty Reads)

一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫做“脏读”。
一句话:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求。

不可重读(Non-Repeatable Reads)

一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。
  一句话:事务A读取到了事务B已经提交的修改数据,不符合隔离性。

幻读(Phantom Reads)

一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
一句话:事务A读取到了事务B提交的新增数据,不符合隔离性。

事务隔离级别及其可以解决的异常

脏读不可重复读幻读
读未提交允许允许允许
读已提交禁止允许允许
可重复读禁止禁止允许
可串行化禁止禁止禁止

索引种类有哪些?

从功能逻辑上说,索引主要有4种,分别是普通索引、唯⼀索引、主键索引和全⽂索引。

  1. 普通索引是基础的索引,没有任何约束,主要⽤于提⾼查询效率。
  2. 唯⼀索引就是在普通索引的基础上增加了数据唯⼀性的约束,在⼀张数据表⾥可以有多个唯⼀索引。
  3. 主键索引在唯⼀索引的基础上增加了不为空的约束,也就是NOT NULL+UNIQUE,⼀张表⾥最多只有⼀个主键索引。
  4. 全⽂索引⽤的不多,MySQL⾃带的全⽂索引只⽀持英⽂。我们通常可以采⽤专⻔的全⽂搜索引擎,⽐如ES(ElasticSearch)和Solr。

mysql聚簇和非聚簇索引的区别

  1. 聚簇索引:将数据存储与索引放到了一块、并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。
  2. 非聚簇索引:叶子节点不存储数据、存储的是数据行地址,也就是说根据索引查找到数据行的位置再取磁盘查找数据,这个就有点类似一本树的目录,比如我们要找第三章第一节,那我们先在这个目录里面找,找到对应的页码后再去对应的页码看文章。

mysql为什么选择B+树作为索引存储结构?

B+ 树满足条件:

  1. 节点的子树数目和关键字数目相同(而B树是子树数目-1)。
  2. 节点的关键字(叫做索引)表示的是子树中的最大数据,在子树中同样含有这个数据。
  3. 叶子节点包含了全部的数据,同时符号从左到右,从小到大的顺序,并用指针连接在一起。

B+树对比B树:

  1. 层级更低(更加矮胖),IO次数更少***。由于 B+ 树的中间节点不含有实际数据,只有子树的最大数据和子树指针,因此磁盘页中可以容纳更多节点元素,也就是说同样数据情况下,B+ 树会 B 树更加“矮胖”,因此查询效率更快。
  2. 每次都需要查询到叶子节点,查询性能稳定*。B树这时就能体现出优势**,由于出现频率较高的树,在B树中往往在上层(非叶子结点),查找到该结点就会成功并结束查询,相对较快。而B+树由于非叶子结点关键字只是代表索引,因此在B+树中,无论查找成功与否,都是走了一条从根到叶子节点的路径。
  3. B+树范围查询更加方便*。 需要查询某个范围内的数据时,由于 B+ 树的叶子节点是一个有序链表,只需在叶子节点上遍历即可,不用像 B 树那样挨个中序遍历**比较大小。

Hash索引与B+树索引的区别

  1. Hash索引不能进⾏范围查询,⽽B+树可以。这是因为Hash索引指向的数据是⽆序的,⽽B+树的叶⼦节
    点是个有序的链表。
  2. Hash索引不⽀持联合索引的最左侧原则(即联合索引的部分索引⽆法使⽤),⽽B+树可以。对于联合索
    引来说,Hash索引在计算 Hash 值的时候是将索引键合并后再⼀起计算 Hash 值,所以不会针对每个索
    引单独计算Hash值。因此如果⽤到联合索引的⼀个或者⼏个索引时,联合索引⽆法被利⽤。
  3. Hash索引不⽀持ORDER BY排序,因为Hash索引指向的数据是⽆序的,因此⽆法起到排序优化的作⽤,
    ⽽B+树索引数据是有序的,可以起到对该字段ORDER BY排序优化的作⽤。同理,我们也⽆法⽤Hash索
    引进⾏模糊查询,⽽B+树使⽤LIKE进⾏模糊查询的时候,LIKE后⾯前模糊查询(⽐如%开头)的话就可
    以起到优化作⽤。

mysql 锁分类

按锁的粒度划分

由小到大为行锁、页锁、表锁,锁定粒度越小,发生锁冲突概率低,可以实现的并发度高,但是对于锁的开销比较大,加锁会比较慢,容易出现死锁情况。mysql InnoDB 引擎支持行锁和表锁,而MyISAM只支持表锁。

每个层级的锁数量是有限制的,因为锁会占用内存空间,锁空间的大小是有限的。当某个层级的锁数量超过了这个层级的阈值时,就会进行锁升级。锁升级就是用更大粒度的锁替代多个更小粒度的锁,比如InnoDB中行锁升级为表锁,这样做的好处是占用的锁空间降低了,但同时数据的并发度也下降了。

从对数据库操作的类型划分

分为读锁和写锁(都属于悲观锁), 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响,写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。

从性能上划分为

乐观锁(Optimistic Locking)认为对同一数据的并发操作不会总发生,属于小概率事件,不用每次都对数据上锁,也就是不采用数据库自身的锁机制,而是通过程序来实现。在程序上,我们可以采用版本号机制或者时间戳机制实现。

在表中设计一个版本字段version,第一次读的时候,会获取version字段的取值。然后对数据进行更新或删除操作时,会执行UPDATE … SET version=version+1 WHERE version=version。此时如果已经有事务对这条数据进行了更改,修改就不会成功。

悲观锁(Pessimistic Locking)也是一种思想,对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性。

MVCC是什么,解决了什么问题

MVCC的英文全称是Multiversion Concurrency Control,中文翻译过来就是多版本并发控制技术。从名字中也能看出来,MVCC是通过数据行的多个版本管理来实现数据库的并发控制,简单来说它的思想就是保存数据的历史版本。这样我们就可以通过比较版本号决定数据是否显示出来(具体的规则后面会介绍到),读取数据的时候不需要加锁也可以保证事务的隔离效果。

通过MVCC我们可以解决以下几个问题:

  1. 读写之间阻塞的问题,通过MVCC可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。
  2. 降低了死锁的概率。这是因为MVCC采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
  3. 解决一致性读的问题。一致性读也被称为快照读,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。

MVCC的核心就是Undo Log+ Read View,“MV”就是通过Undo Log来保存数据的历史版本,实现多版本的管理,“CC”是通过Read View来实现管理,通过Read View原则来决定数据是否显示。同时针对不同的隔离级别,Read View的生成策略不同,也就实现了不同的隔离级别。

数据库主从同步的作用

  1. 首先是可以读写分离。我们可以通过主从复制的方式来同步数据,然后通过读写分离提高数据库并发处理能力。
  2. 第二个作用就是数据备份。我们通过主从复制将主库上的数据复制到了从库上,相当于是一种热备份机制,也就是在主库正常运行的情况下进行的备份,不会影响到服务。
  3. 第三个作用是具有高可用性。数据备份实际上是一种冗余的机制,通过这种冗余的方式可以换取数据库的高可用性,也就是当服务器出现故障或宕机的情况下,可以切换到从服务器上,保证服务的正常运行。

主从同步原理

主从同步的原理就是基于Binlog进行数据同步的。在主从复制过程中,会基于3个线程来操作,一个主库线程,两个从库线程。

二进制日志转储线程(Binlog dump thread)是一个主库线程。当从库线程连接的时候,主库可以将二进制日志发送给从库,当主库读取事件的时候,会在Binlog上加锁,读取完成之后,再将锁释放掉。

从库I/O线程会连接到主库,向主库发送请求更新Binlog。这时从库的I/O线程就可以读取到主库的二进制日志转储线程发送的Binlog更新部分,并且拷贝到本地形成中继日志(Relay log)。

从库SQL线程会读取从库中的中继日志,并且执行日志中的事件,从而将从库中的数据与主库保持同步。

如何解决主从同步的数据一致性问题

异步复制

异步模式就是客户端提交COMMIT之后不需要等从库返回任何结果,而是直接将结果返回给客户端,这样做的好处是不会影响主库写的效率,但可能会存在主库宕机,而Binlog还没有同步到从库的情况,也就是此时的主库和从库数据不一致。这时候从从库中选择一个作为新主,那么新主则可能缺少原来主服务器中已提交的事务。所以,这种复制模式下的数据一致性是最弱的。

半同步复制

MySQL5.5版本之后开始支持半同步复制的方式。原理是在客户端提交COMMIT之后不直接将结果返回给客户端,而是等待至少有一个从库接收到了Binlog,并且写入到中继日志中,再返回给客户端。这样做的好处就是提高了数据的一致性,当然相比于异步复制来说,至少多增加了一个网络连接的延迟,降低了主库写的效率。

在MySQL5.7版本中还增加了一个rpl_semi_sync_master_wait_for_slave_count参数,我们可以对应答的从库数量进行设置,默认为1,也就是说只要有1个从库进行了响应,就可以返回给客户端。如果将这个参数调大,可以提升数据一致性的强度,但也会增加主库等待从库响应的时间。

组复制

组复制技术,简称MGR(MySQL Group Replication)。是MySQL在5.7.17版本中推出的一种新的数据复制技术,这种复制技术是基于Paxos协议的状态机复制。

将多个节点共同组成一个复制组,在执行读写(RW)事务的时候,需要通过一致性协议层(Consensus层)的同意,也就是读写事务想要进行提交,必须要经过组里“大多数人”(对应Node节点)的同意,大多数指的是同意的节点数量需要大于(N/2+1),这样才可以进行提交,而不是原发起方一个说了算。而针对只读(RO)事务则不需要经过组内同意,直接COMMIT即可。

在一个复制组内有多个节点组成,它们各自维护了自己的数据副本,并且在一致性协议层实现了原子消息和全局有序消息,从而保证组内数据的一致性。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值