【java八股文】之MYSQL基础篇

1、数据库三大范式是什么

第一范式:每个列都不可以再拆分。

第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。

第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我 们经常会为了性能而妥协数据库的设计。

2、说一说B和B+树的区别

B树的数据即存在非叶子节点上也存在于叶子节点上,而B+树所有的数据都是存在叶子节点。就是因为这个原因所以B+树存储的数据比较多,因为一个页的大小是16KB而B树的非叶子节点又存储了数据data,所以一个页存储的节点少一些,故如果使用B树那么层数会相应提高很多。

B+树的叶子节点还采用了双向链表的结构,这样也可以可以方便使用范围查找和所有数据的遍历。而B树有的数据存储在非叶子节点就做不到这一点,必须经过不断的回溯IO大大降低了效率

  • 二叉树(形成一条链表的形式)
  • 红黑树(树的高度太深)
  • Hash(不支持范围的查找)


3、MyISAM 和 InnoDB的区别

  • 存储的文件格式: MyISAM 存储索引MYI 存储数据MYD 存储表的结构frm;InnoDB存储的索引+数据都是IDB 存储表的结构frm
  • 索引存储方式:MyISAM 存储的是那条记录的地址(非聚簇索引)InnoDB存储的是那条记录的所有值(聚簇索引)
  • 事务:InnoDB支持事务,MyISAM 不支持事务
  • 外键:InnoDB支持外键,MyISAM 不支持外键
  • 锁:InnoDB支持行锁和表锁,MyISAM 只支持表锁

4、什么是聚簇索引和非聚簇索引和覆盖索引

聚簇索引:就是将索引和值放在一起,根据索引可以直接获取值,

非主键索引:叶子节点存放的是数据行地址,先根据索引找到数据地址,再根据地址找数据

覆盖索引:覆盖索引就是所查找的结果集,在所查找的索引树当中已经存在了不用再进行回表操作

联合索引:多个字段联合起来的索引

5、除了索引我们写SQL时候还有那些优化

  • 要遵循最左前缀法则
  • 使用覆盖索引,就是查询字段需要指定明确,切忌不要使用 *
  • in 后面中的字段尽量少,不宜过多,发现数据较少
  • 注意范围查询语句,一般返回查询语句的后面字段会索引失效
  • 不建议使用%前缀模糊查询
  • 避免在where子句中,对字段进行null判断,,这样会造成不走索引
  • 避免where子句中对字段表达式函数的操作,字符串不加单引号
  • 尽量避免where子句使用or 判断,因为or左右只有有一方没有索引,就会导致全表扫描
  • 尽量使用inner join 避免使用left join因为是小表为驱动表,而left join是左表驱动右表

6、NLJ BNL 算法

通常使用小表使用驱动表,被驱动表字段如果不存在索引使用BNL算法,否则时候NLJ算法,因为他们扫描次行数相等,这个时候BNL算法的磁盘扫描而且扫描次数更少,他是先从磁盘中放入join_buffer中去,而且计算快得多。

7、为什么小表作为驱动表

驱动表首先会根据where字段进行过滤,然后再去跟非驱动表进行join关联的。

大表 1000 小表 100行记录

关联过程:

NLJ算法: 这个通常是在被驱动表关联字段存在索引情况下触发,首先将驱动表查询好的字段取出来(100次),然后因为有索引所以每一行查询好关联的记录去被驱动表(100)次。总共 100+100 = 200次

BNL算法: 把驱动表筛选出来的数据读取到join_buffer中去(100次),将大表的每一行取出来拿出来join_buffer每一行进行对比(100 * 1000)。如果join_buffer存不下去,那么分多次磁盘的IO读写进行和被驱动表对比。

8、索引下推

就是当一个联合索引,第一个是模糊查询,导致后面的字段不能够使用索引 ,这个时候将索引查询到的数据进行回表操作,这个时候的回标任务比较大。所以MySQL自动优化采用了索引下推的机制,在筛选模糊查询的时候也进一步去筛选模糊查询后面的字段,这样可以大大的减少了回表的成本。

9、MySQL的事务特性

  • 原子性:就是一个事务一系列的操作命令要么全部执行,要么全部执行失败。通过Undolog日志解决
  • 持久性:事务一旦提交就不可改变,而且必须持久化到磁盘当中。通过Redolog日志解决
  • 一致性:再一个事务对数据的查询结果必须是一致的。MVCC,通过Undolog日志解决
  • 隔离性:事务和事务之间互不影响。这个我们可以通过加锁来解决
  • 读未提交:再这个隔离级别下,所有的事务都可以看到其他事务没有提交的执行结果。就会出现脏读、不可重复读、幻读
  • 读已提交:这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。就会出现不可重复读、幻读
  • 可重复读:事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。幻读
  • 串行化:确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。


10、使用索引就一定比没有使用索引好吗?

空间上的代价:每建立一个索引都要为它建立一棵B+树,每一棵B+树的每一个节点都是一个数据页,一个页默认会占用 16KB 的存储空间,一棵很大的B+树由许多数据页组成,那就是很大的一片存储空间。

时间上的代价:每次对表中的数据进行 增、删、改 操作时,所以存储引擎需要额外的时间进行一些记录移位 ,页面分裂 、页面回收等操作来维护好节点和记录的排序。如果我们建了许多索引,每个索引对应的B+树都要进行相关的维护操作,会给性能拖后腿。

11、redolog好处

防止实例挂了或者宕机,这样就会丢失掉那一段时间的数据。有了redolog日志就直接降低了刷盘的频率。

三种输盘策略:redo log buffer -> page cache -> 磁盘

  • 1 提交事务立马刷盘
  • 0 不刷盘,每个1s进行刷盘操作
  • 2 不刷盘,由OS操作系统决定刷盘

12、结合redolog和undolog 说一说一条sql 的执行过程

从磁盘中加载数据到buffer pool中
记录Undolog日志
更新buffer pool中的数据
记录redolog日志就是将更新的操作写入redolog buffer中
redolog buffer 写入 到redolog文件
记录binlog日志(刷盘)

【java八股文】之MYSQL基础篇_第1张图片

【java八股文】之MYSQL基础篇_第2张图片


13、MySQL锁的分类


基于属性:

  • 共享锁(读锁):又称读锁,一个事务为表加了读锁,其它事务只能加读锁,不能加写锁
  • 排他锁(写锁):又称写锁,一个事务加写锁之后,其他事务不能再加任何锁,避免脏读问题


基于粒度:

  • 表锁(这个是串行化):对整张表加锁,粒度大并发小
  • 行锁(可以解决可重复读):对行加锁,粒度小并发大
  • 间隙锁(可以解决幻读):间隙锁,锁住表的一个区间,间隙锁之间不会冲突只在可重复读下才生效,解决了幻读
  • 临键锁(可以解决幻读 和 可重复读):是行锁和间隙锁的一种结合方式


14、什么是MVCC

MVCC是多版本控制,我们在解决隔离级别产生问题的时候,一般有两种方式

  • 是通过加锁的方式
  • 通过MVCC版本控制,这种因为是没有加锁,所以并发量高,性能更好,不用去阻塞其他线程和事务的操作

在每次的事务当中都会生成一个新版本ReadView的数据:

  • 在读应提交的隔离级别下,每次的读都会生成一个新的ReadView规则,然后遵循ReadView版本链去获取读到的数据,这种情况可以解决可重复读的问题
  • 在可重复读的隔离级别下,每次读只有在第一次的读过程中才会产生一个ReadView规则的undolog版本链,这种情况就可以解决幻读的情况。


15、select 的执行原理(顺序)

SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT...

这条sql 的执行步骤

FROM   ->  JOIN  ->  ON  ->  WHERE  ->  GROUP BY  ->  HAVING   ->  
SELECT   ->  DISTINCT  ->  ORDER BY  -> LIMIT

客户端 -> 连接器 -> 词法分析器 -> 优化器 -> 执行器 -> 存储引擎

连接器:如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。

16、char和varchar区别

char是固定长度的不可变的,varchar是可变的字符串
char存储短的字符会造成空间的浪费,但是性能优于varchar,varchar类型是长度变化的所以存入和取出来的时候性能上还要进一步的去判断长度大小所以性能效率上相对于会低。
char列的长度是固定的,能存取的最大的长度是0~255之间,如果存储的是utf8那么就是3*255的字节;如果是GBK那么就是2*255

varchar分为两个部分存储,一个是存储数据一个是存储长度范围的,以前的最大长度是255 ,mysql5版本后就是0~65535(2^16)个字节 ,例外还需要1-2个字节(长度超过255时需要2个字节)来存储字符串的实际长度。

17、binlog日志的用途

  • 数据的备份(防止数据丢失)
  • 数据的复制(主从机的复制)
  • Statement:每一条会修改数据的sql都会记录在binlog中。优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
  • Row:它不记录sql语句上下文相关信息,仅保存哪条记录被修改。优点:row level 的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题。
  • Mixed:从5.1.8版本开始,MySQL提供了Mixed格式,实际上就是Statement与Row的结合。


18、如果我们发现一条Sql执行特别慢 我们该怎么去处理

我们先观察服务器的状态情况看是否是在周期性的波动情况,如果是那么看加缓存能不能解决掉
如果不能解决那么我们开启慢查询,分析慢查询的语句。看是SQL的执行时间长问题,还是SQL语句的等待过长原因。
如果是等待过长就调优服务器的参数,如果是SQL语句的原因那么我们就优化SQL语句,比如加索引优化啊数据库表的设计优化
如果上面还是不能解决,看SQL查询是否达到了瓶颈,如果是就读写分离(主从架构)分库分表(垂直分表,垂直分库,水平分表)
查看系统性能参数 SHOW [GLOBAL|SESSION] STATUS LIKE '参数';

统计SQL的查询成本 SHOW STATUS LIKE 'last_query_cost';

开启慢查询日志参数 set global slow_query_log='ON';

设置慢查询的时间阈值 set global long_query_time = 1;

查询有多少条慢查询的记录 SHOW GLOBAL STATUS LIKE '%Slow_queries%';

查看 SQL 执行成本 SHOW PROFILE

分析查询语句 EXPLAIN

19、哪些情况索引会失效


(1)where条件中有or,除非所有查询条件都有索引,否则失效

(2)like查询用%开头,索引失效

(3)索引列参与计算,索引失效

(4)违背最左匹配原则,索引失效

(5)索引字段发生类型转换,索引失效

(6)mysql觉得全表扫描更快时(数据少),索引失效
 

你可能感兴趣的:(java,MYSQL,java,mysql,开发语言)