面试必背-MySql八股文(2)

1.数据库的锁

1.1 什么是数据库的锁?

当数据库有并发事务的时候,保证数据访问顺序的机制称为锁机制。

数据库的锁与隔离级别的关系?

面试必背-MySql八股文(2)_第1张图片

 1.2 数据库锁的类型有哪些?

Mysql锁类别 资源开销 加锁速度 是否会出现死锁 锁的粒度 并发度
表级锁 不会
行级锁
页面锁 一般 一般 不会 一般 一般

MyISAM 默认采用表级锁,InnoDB 默认采用行级锁。

从锁的类别上区别可以分为共享锁和排他锁

  • 共享锁:共享锁又称读锁,简写为S锁,一个事务对一个数据对象加了S锁,可以对这个数据对象进行读取操作,但不能进行更新操作。并且在加锁期间其他事务只能对这个数据对象加S锁,不能加X锁。

  • 排他锁:排他锁又称为写锁,简写为X锁,一个事务对一个数据对象加了X锁,可以对这个对象进行读取和更新操作,加锁期间,其他事务不能对该数据对象进行加X锁或S锁。

1.3 什么是数据库的乐观锁和悲观锁,如何实现? 

乐观锁:系统假设数据的更新在大多数时候是不会产生冲突的,所以数据库只在更新操作提交的时候对数据检测冲突,如果存在冲突,则数据更新失败。

乐观锁实现方式:一般通过版本号和CAS算法实现。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。通俗讲就是每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。

悲观锁的实现方式:通过数据库的锁机制实现,对查询语句添加for updata。

1.4 什么是死锁?如何避免?

死锁是指两个或者两个以上进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。在 MySQL 中,MyISAM 是一次获得所需的全部锁,要么全部满足,要么等待,所以不会出现死锁。在 InnoDB 存储引擎中,除了单个 SQL 组成的事务外,锁都是逐步获得的,所以存在死锁问题。

如何避免MySQL发生死锁或锁冲突:

  1. 如果不同的程序并发存取多个表,尽量以相同的顺序访问表。

  2. 在程序以批量方式处理数据的时候,如果已经对数据排序,尽量保证每个线程按照固定的顺序来处理记录。

  3. 在事务中,如果需要更新记录,应直接申请足够级别的排他锁,而不应该先申请共享锁,更新时在申请排他锁,因为在当前用户申请排他锁时,其他事务可能已经获得了相同记录的共享锁,从而造成锁冲突或者死锁。

  4. 尽量使用较低的隔离级别。2

  5. 尽量使用索引访问数据,使加锁更加准确,从而减少锁冲突的机会。

  6. 合理选择事务的大小,小事务发生锁冲突的概率更低。

  7. 尽量用相等的条件访问数据,可以避免Next-Key锁对并发插入的影响。

  8. 不要申请超过实际需要的锁级别,查询时尽量不要显示加锁。

  9. 对于一些特定的事务,可以表锁来提高处理速度或减少死锁的概率。

2. B 树和 B+ 树的区别?

  • B 树中的内部节点和叶子节点均存放键和值,而 B+ 树的内部节点只有键没有值,叶子节点存放所有的键和值。

  • B+ 树的叶子节点是通过相连在一起的,方便顺序检索。面试必背-MySql八股文(2)_第2张图片

3. 数据库为什么使用 B+ 树而不是 B 树?

  • B 树适用于随机检索,而 B+ 树适用于随机检索和顺序检索。

  • B+ 树的空间利用率更高,因为 B 树每个节点要存储键和值,而 B+ 树的内部节点只存储键,这样 B+ 树的一个节点就可以存储更多的索引,从而使树的高度变低,减少了 I/O 次数,使得数据检索速度更快。

  • B+ 树的叶子节点都是连接在一起的,所以范围查找,顺序查找更加方便。

  • B+ 树的性能更加稳定,因为在 B+ 树中,每次查询都是从根节点到叶子节点,而在 B 树中,要查询的值可能不在叶子节点,在内部节点就已经找到。

3.1 什么情况适合使用 B 树呢?

因为 B 树的内部节点也可以存储值,所以可以把一些频繁访问的值放在距离根节点比较近的地方,这样就可以提高查询效率。

4.MySQL执行SQL语句的的流程?

面试必背-MySql八股文(2)_第3张图片

  • 1.通过连接器跟客户端「建立连接」。

  • 2.通过查询「缓存查询」之前是否有查询过该 sql。

    • 有则直接返回结果

    • 没有则执行第3步

  • 3.通过分析器「分析该 sql 的语义」是否正确,包括格式,表等等。

  • 4.通过优化器「优化该语句」,比如选择索引,join 表的连接顺序。

  • 5.「验证权限」,验证是否有该表的查询权限。

    • 没有则返回无权限的错误

    • 有则执行第6步

  • 6.通过执行器调用存储引擎执行该 sql,然后返回「执行结果」。

5.binlog、undolog、relaylog、redolog?

 

        1.binlog 是归档日志,属于 Server 层的日志,是一个二进制格式的文件,用于「记录用户对数据库更新的SQL语句信息」。

主要作用:主从复制、数据恢复。

        2.undolog 是 InnoDB 存储引擎的日志,用于保证数据的原子性,「保存了事务发生之前的数据的一个版本,也就是说记录的是数据是修改之前的数据,可以用于回滚」,同时可以提供多版本并发控制下的读(MVCC)。

主要作用:事务回滚、实现多版本控制(MVCC)。

        3.relaylog 是中继日志,「在主从同步的时候使用到」,它是一个中介临时的日志文件,用于存储从master节点同步过来的binlog日志内容。

        4.redolog 是 「InnoDB 存储引擎所特有的一种日志」,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。

可以做「数据恢复并且提供 crash-safe 能力」。当有增删改相关的操作时,会先记录到 Innodb 中,并修改缓存页中的数据,「等到 mysql 闲下来的时候才会真正的将 redolog 中的数据写入到磁盘当中」。

6.两阶段提交

两阶段提交分为 prepare 和 commit 阶段:

  1. 准备阶段:事物 SQL 先写入 redo log buffer,然后做一个事物准备标记,在将log buffer 中的数据刷新到 redo log。

  • 提交阶段:将事物产生的 binlog 写入文件,刷新磁盘。

        2.再在 redo log 中做一个事物提交的标记,并把 binlog 写成功的标记也一并写入 redo log 文件。

场景分析两阶段提交如何保证数据库的一致性。

  1. 准备阶段,redo log 刷新到磁盘了,但是 binlog 写磁盘前发生了 mysql实例 crash,这时会发生怎样的操作呢?

  • 即使 redo log 写盘成功了,但由于 binlog 未写入成功,需要执行回滚操作来保证数据库的一致性。

        2.提交阶段,binlog 写盘成功了,这时 mysql 实例 crash了。这时 binlog 已经确保写成功了,我们在重启实例进行恢复的时候,只需要让 redo log 重做一次就可以了。

7.分库分表

7.1分库分表方案

水平分库:以字段为依据,按照一定策略(hash、range等),将一个库中的数据拆分到多个库中。水平分表:以字段为依据,按照一定策略(hash、range等),将一个表中的数据拆分到多个表中。垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。垂直分表:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。

7.2 常用的分库分表中间件

  • sharding-jdbc

  • Mycat

7.3分库分表可能遇到的问题

  • 事务问题:需要用分布式事务。

  • 跨节点Join的问题:解决这一问题可以分两次查询实现。

  • 跨节点的count,order by,group by以及聚合函数问题:分别在各个节点上得到结果后在应用程序端进行合并。

  • 数据迁移,容量规划,扩容等问题。

  • ID问题:数据库被切分后,不能再依赖数据库自身的主键生成机制啦,最简单可以考虑UUID。

  • 跨分片的排序分页问题。

7.4数据库如何进行垂直拆分以及水平拆分的原理是什么?

垂直拆分

  • 专库专用 一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面

优点:

  1. 拆分后业务清晰,拆分规则明确。

  2. 系统之间整合或扩展容易。

  3. 数据维护简单。

缺点:

  1. 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度。

  2. 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高。

  3. 事务处理复杂。

水平拆分

垂直拆分后遇到单机瓶颈,可以使用水平拆分。相对于垂直拆分的区别是:垂直拆分是把不同的表拆到不同的数据库中,而水平拆分是把同一个表拆到不同的数据库中。

相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中,主要有分表,分库两种模式,

优点:

  1. 不存在单库大数据,高并发的性能瓶颈。

  2. 对应用透明,应用端改造较少。

  3. 按照合理拆分规则拆分,join操作基本避免跨库。

  4. 提高了系统的稳定性跟负载能力。

缺点:

  1. 拆分规则难以抽象。

  2. 分片事务一致性难以解决。

  3. 数据多次扩展难度跟维护量极大。

  4. 跨库join性能较差。

8.Mysql 主从之间是怎么同步数据的?

1.master 主库将此次更新的事件类型「写入到主库的 binlog 文件」中。

2.master 「创建 log dump 线程通知 slave」 需要更新数据。

3.「slave」 向 master 节点发送请求,「将该 binlog 文件内容存到本地的 relaylog 中」。

4.「slave 开启 sql 线程」读取 relaylog 中的内容,「将其中的内容在本地重新执行一遍」,完成主从数据同步。

面试必背-MySql八股文(2)_第4张图片

 8.1 同步策略

1.「全同步复制」:主库强制同步日志到从库,等全部从库执行完才返回客户端,性能差。2.「半同步复制」:主库收到至少一个从库确认就认为操作成功,从库写入日志成功返回ack确认。

8.2主从延迟要怎么解决?

面试必背-MySql八股文(2)_第5张图片

 

  1. 主库的更新事件(update、insert、delete)被写到binlog。

  2. 从库发起连接,连接到主库。

  3. 此时主库创建一个binlog dump thread,把binlog的内容发送到从库。

  4. 从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log。

  5. 还会创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db。

主从同步延迟的原因:

一个服务器开放N个链接给客户端来连接的,这样有会有大并发的更新操作, 但是从服务器的里面读取binlog的线程仅有一个,当某个SQL在从服务器上执行的时间稍长 或者由于某个SQL要进行锁表就会导致,主服务器的SQL大量积压,未被同步到从服务器里。这就导致了主从不一致, 也就是主从延迟。

主从同步延迟的解决办法

1.MySQL 5.6 版本以后,提供了一种「并行复制」的方式,通过将 SQL 线程转换为多个 work 线程来进行重放。2.「提高机器配置」增加从服务器,目的分散读的压力,从而降低服务器负载。3.在业务初期就选择合适的分库、分表策略,「避免单表单库过大」带来额外的复制压力 4.「避免长事务」。5.「避免让数据库进行各种大量运算」。6.对于一些对延迟很敏感的业务「直接使用主库读」。

9.如何优化 SQL,说说你的 Sql 调优思路吧

  • 「表结构优化」

    • 拆分字段

    • 字段类型的选择

    • 字段类型大小的限制

    • 合理的增加冗余字段

    • 新建字段一定要有默认值

  • 「索引方面」

    • 索引字段的选择

    • 利用好mysql支持的索引下推,覆盖索引等功能

    • 唯一索引和普通索引的选择

  • 「查询语句方面」

    • 避免索引失效

    • 合理的书写where条件字段顺序

    • 小表驱动大表

    • 可以使用force index()防止优化器选错索引

  • 「分库分表」

10.了解慢日志查询吗?统计过慢查询吗?对慢查询如何优化?

慢查询一般用于记录执行时间超过某个临界值的SQL语句的日志。

相关参数:

slow_query_log:是否开启慢日志查询,1表示开启,0表示关闭。slow_query_log_file:MySQL数据库慢查询日志存储路径。long_query_time:慢查询阈值,当SQL语句查询时间大于阈值,会被记录在日志上。log_queries_not_using_indexes:未使用索引的查询会被记录到慢查询日志中。log_output:日志存储方式。“FILE”表示将日志存入文件。“TABLE”表示将日志存入数据库。如何对慢查询进行优化?

分析语句的执行计划,查看SQL语句的索引是否命中 优化数据库的结构,将字段很多的表分解成多个表,或者考虑建立中间表。优化LIMIT分页。

11.字段为什么要设置成 not null?

首先说一点,NULL和空值是不一样的,空值是不占用空间的,而NULL是占用空间的,所以字段设为NOT NULL后仍然可以插入空值。

字段设置成not null主要有以下几点原因:

NULL值会影响一些函数的统计,如count,遇到NULL值,这条记录不会统计在内。

B树不存储NULL,所以索引用不到NULL,会造成第一点中说的统计不到的问题。

NOT IN子查询在有NULL值的情况下返回的结果都是空值。

12.varchar和char的区别?

varchar表示变长,char表示长度固定。

存储容量不同,对于 char 来说,最多能存放的字符个数为255。对于 varchar,最多能存放的字符个数是 65532。

存储速度不同,char 长度固定,存储速度会比 varchar 快一些,但在空间上会占用额外的空间,属于一种空间换时间的策略。而 varchar 空间利用率会高些,但存储速度慢,属于一种时间换空间的策略。

12.1为什么 VarChar 建议不要超过255?

  • 当定义varchar长度小于等于255时,长度标识位需要一个字节(utf-8编码)。

  • 当大于255时,长度标识位需要两个字节,并且建立的索引也会失效。

12.2varchar(10)和int(10)代表什么含义?

  • varchar 的10代表了申请的空间长度,也是可以存储的数据的最大长度。

  • int 的10只是代表了展示的长度,不足10位以0填充。

  • int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示。

13.  drop、delete和truncate的区别?

drop delete truncate
速度 逐行删除,慢 较快
类型 DDL DML DDL
回滚 不可回滚 可回滚 不可回滚
删除内容 删除整个表,数据行、索引都会被删除 表结构还在,删除表的一部分或全部数据 表结构还在,删除表的全部数据

总结:删除整个表,使用drop,删除表的部分数据使用delete,保留表结构删除表的全部数据使用truncate。

14. 对慢查询如何优化?

慢查询一般用于记录执行时间超过某个临界值的SQL语句的日志。

14.1 如何查找查询速度慢的原因?

  1. 记录慢查询日志,分析查询日志,可以使用pt-query-digest工具进行分析。

相关参数:

  • slow_query_log:是否开启慢日志查询,1表示开启,0表示关闭。

  • slow_query_log_file:MySQL数据库慢查询日志存储路径。

  • long_query_time:慢查询阈值,当SQL语句查询时间大于阈值,会被记录在日志上。

  • log_queries_not_using_indexes:未使用索引的查询会被记录到慢查询日志中。

  • log_output:日志存储方式。“FILE”表示将日志存入文件。“TABLE”表示将日志存入数据库。

2.show profile

3.show status

show status 会返回一些计数器,show global status 会查看所有服务器级别的所有计数。有时根据这些计数,可以推测出哪些操作代价较高或者消耗时间多。

4.show processlist

观察是否有大量线程处于不正常的状态或特征

5.使用 explain 分析语句

分析慢语句是否命中索引

 14.2如何对慢查询进行优化?

  • 分析语句的执行计划,查看SQL语句的索引是否命中。

  • 优化数据库的结构,将字段很多的表分解成多个表,或者考虑建立中间表。

  • 优化LIMIT分页。

图片及部分相关技术知识点来源于网络搜索,侵权删!

你可能感兴趣的:(面试题,面试,mysql,java)