八股文(MySQL数据库篇)

第一章:基础知识

MYSQL都有哪些数据类型?

数值类型

TINYINT,SMALLINT,MEDUIINT,BIGINT

任何数据都可以指定长度,不是指定合法长度,而是限制了显示长度

字符串类型

CHAR,VARCHAR,TXT

区别
  1. CHAR是定长,VARCHAR是变长;
  2. VARCHAR对每个字符均是两个字节
  3. 短数据,并且经常需要更改的使用CHAR更好
  4. 效率区别:CHAR>VARCHAR>TEXT
  5. CHAR和VARCHAR支持默认值,VARCHAR不支持
  6. TEXT最大支持4G,适合大数据存储

范式

第一范式:不会有重复的列,体现原子性
第二范式:存在主键,体现唯一性
第三范式:非主属性必须互不依赖

范式和反范式的优缺点

范式:范式化的表减少了数据冗余,更新操作快,占用存储时间少
缺点:经常需要多表查询
反范式:查询表较快
缺点:存在大量冗余数据,数据的维护成本更高

第二章:索引

定义

索引是对数据库中一列或多列的值进行排序的数据结构,用于快速访问数据表中的特定结构

分类

聚簇非聚簇:聚簇索引值的逻辑顺序与表中相应行顺序不一致

优缺点

优点:大大加快检索速度,通过创建唯一性索引,可以保证数据表中每一行数据的唯一性
缺点:索引本身需要空间,聚簇索引会更大;创建和维护索引需要时间

索引设计原则

  • 选择唯一性索引
  • 经常查询的表简历索引
  • 小表不建议索引
  • 尽量使用数据量少的索引
  • 频繁修改的不建议用索引

索引的数据结构

Hash

由于Hash的随机特性,一定范围的值在hash映射后范围不一致,所以无法范围查询,只能等值查询

B+树
  1. 本质上是一颗查找树,支持范围查询和排序
  2. 查询效率比较稳定
  3. 与B树的区别:所有关键字存储在叶子结点出现,内部结点(非叶子结点并不存储真正的data),为所有结点增加了一个链指针。与B树相比好在:B+数减少了IO次数,B+树查询效率更稳定,B+树支持范围查询
最左匹配原则:

我们看到 最左边的a 都是有序的,分别是 : 1,1,2,2,3,3 但是右边的b 不一定有序: 1,2,1,4,3,2
但是在a都为 1 的情况下 b是有序的, 如: a=1时 b =1,2 ; a=2时, b= 1,4; a=3时 ,b=1,2;

覆盖索引

覆盖索引指的是在索引树中,所有需要查询的列都能够通过B+树的叶子节点来完成查询,而不必再回到数据页中查找对应的数据行。因此,覆盖索引可以大幅度减少磁盘IO的次数,从而提高查询效率。

索引下推

MySQL 服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合 MySQL 服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给 MySQL 服务器。索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少 MySQL 服务器从存储引擎接收数据的次数。

为何使用B+树不用二叉查找树

假设一个页内的数据过少,那么操作系统就需要读取更多的页,涉及磁盘随机 I/O 访问的次数就更多。将数据从磁盘读入内存涉及随机 I/O 的访问,是数据库里面成本最高的操作之一。因而这种树高会随数据量增多急剧增加,每次更新数据又需要通过左旋和右旋维护平衡的二叉树,不太适合用于存储在磁盘上的索引文件

第三章:存储

InnoDB

特性
  • 预读
  • 插入缓冲
  • 自适应哈希
    -二次写
和MyISAM的区别

InnoDB支持事务,支持外键,MyISAM不支持
InnoDB 和 MyISAM 均支持 B+ Tree 数据结构的索引。但 InnoDB 是聚集索引,而 MyISAM 是非聚集索引。具体体现在Innodb的数据文件和索引文件绑定在一起,而mysiam索引和数据是分离的,索引保存的是数据文件的指针

InnoDB为何推荐使用自增主键?

InnoDB推荐使用自增主键的原因主要是为了提高写入效率和避免数据碎片。因为InnoDB的数据结构是B+树,如果使用自增主键,那么每次插入数据都会在B+树的最右边,不会导致树的分裂和重平衡。而如果使用非自增的主键或者没有指定主键,那么每次插入数据都可能会在B+树中间或者随机位置,导致树的结构变化和空间浪费。

InnoDB线程
  • 负责刷新内存池中的数据,保证缓冲池的内存缓冲的是最近的数据
  • 已修改的数据文件刷新到磁盘
  • 保证数据库发生异常的情况下innodb能恢复到正常状态
自适应哈希

InnoDB 会监控对表上各索引页的查询执行情况,如发现建立哈希索引可以提升速度,则建立哈希索引,这是过程不需要用户干预。

存储结构

具体结构

页:和内存的页类似
区:区是页的集合
段:B+ 树将数据分为了两部分,叶子节点部分和非叶子节点部分,也就我们要介绍的段 Segment,也就是说 InnoBD 中每一个索引都会创建两个Segment段来存放对应的两部分数据

Buffer Pool

定义:Buffer Pool 是 InnoDB 存储引擎层的缓冲池
预读机制:线性预读(程序的局部性原理):线性预读认为如果前面的请求顺序访问当前区(extent)的页,那么接下来的若干请求也会顺序访问下一个区的页,并将下一个区加载到 Buffer Pool。

换页算法:

预读失效:要优化预读失效,则让预读失败的页停留在缓冲池里的时间尽可能短,预读成功的页停留时间尽可能长。具体将 LRU 链分代实现,即新生代和老年代(old subList),预读的页加入缓冲池时只加入到老年代头部,只有真正被预读成功,则再加入新生代。
缓冲池污染:当批量扫描大量数据时,可能导致把缓冲池的所有页都替换出去,导致大量热数据被换出,MySQL 性能急剧下降。
InnoDB 缓冲池加入了一个老生代停留时间窗口的机制,只有满足预读成功并且在老生代停留时间大于该窗口才会被放入新生代头部

第四章:事务

定义:事务是逻辑上的一组操作,要么都执行,要么都不执行

什么是脏读、幻读和不可重复读?

脏读:事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的
幻读:一个事务中两次读取的数据量不一致。 系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
不可重复读:一个事务中两次读取的数据的内容不一致。 事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据作了更新并提交,导致事务 A 多次读取同一数据时,结果 不一致。

定义:当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。即锁的作用是解决并发问题。

分类

从粒度分
  • 行级锁:行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。
  • 页级锁:是粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折中的页级,一次锁定相邻的一组记录。
  • 表级锁:是粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。
从使用性质分
  • 共享锁:无论是行级或是表级 ,如果对某数据上了共享读锁 ,其他事务可以继续读(也就是允许持有共享读锁),但是 不能写,也就是读写互斥。
  • 排他锁:当事务对某数据加上了 独占写锁 (排他锁) ,只有当前事务能够对这数据执行修改或删除操作。
    其他事务,不能读,不能写 。因为 这个锁很独, 必须等这个很独的锁使用完了(释放),其他事务才有机可乘。
  • 更新锁:更新锁定是共享锁定和排他锁定的混合。共享锁是在DML执行之前进行更改之前使用的。其他事务可以读取锁定的数据,但不能修改它。一旦修改开始,它就成为一个排他锁,其他事务直到事务结束后才能读取和更新锁定的数据。因此,更新锁可以避免造成死锁。
从主观上分
  • 乐观锁:认为别的线程不会同时修改数据,只有到数据提交的时候才通过CAS机制来验证数据是否存在冲突。
  • 悲观锁:具有强烈的独占和排它特性,每次读取数据时都会认为会被其它事务修改,所以每次操作都需要加上锁。

快照读和当前读

快照读就是读取的是快照数据,不加锁的简单 Select 都属于快照读。
当前读就是读的是最新数据,而不是历史的数据。加锁的 SELECT,或者对数据进行增删改都会进行当前读。

第五章:视图

存储过程:

定义:存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需要创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。

与函数的区别

1.返回值不同 函数只有一个返回值,而存储过程通过参数返回,可以有多个也可以没有
2.参数不同 函数可以在查询语句中字节调用,而存储过程必须单独调用

第六章:集群

日志

  • 重做日志:在MySQL中事务执行 commit 提交了之后,但是服务器宕机了,数据还没有写入磁盘,在MySQL重启服务之后会重新执行这个重做日志写入数据。
  • 回滚日志: 保存了事务发生之前的数据的一个版本,可以用于回滚
  • 错误日志:记录 MySQL 启动和停止,以及服务器在运行过程中发生的错误的相关信息
  • 二进制日志:是MySQL数据库级别的文件,记录对MySQL数据库执行修改的所有操作,不会记录select和show语句,主要用于恢复数据库和同步数据库
重做日志和二进制日志有什么区别?

二进制日志会记录所有日志记录,包括InnoDB、MyISAM等存储引擎的日志;重做日志只记录innoDB自身的事务日志。
二进制只在事务提交前写入到磁盘,一个事务只写一次;而在事务进行过程,会有重做日志不断写入磁盘。

主从复制

定义:主从复制是用来建立一个与主数据库完全一样的数据库环境,即从数据库。主数据库一般是准实时的业务数据库
作用:读写分离,使数据库能支撑更大的并发;高可用,做数据的热备,作为后备数据库,主数据库故障可以切换到从数据库

架构
  • 一主一从或一主多从:
  • 主主复制:双主复制架构适用于需要进行主从切换的场景。 两个数据库互为主从,当主库宕机恢复后,由于它还是原来从库(现在主库)的从机,所以它还是会复制新的主库上的数据。那么无论主库的角色怎么切换,原来的主库都不会脱离复制环境。
  • 连级复制:联级复制架构只是在一主多从的基础上,再主库和各个从库之间增加了一个二级主库 Master2,这个二级主库仅仅用来将一级主库推送给它的 Binlog 日志再推送给各个从库,以此来减轻一级主库的推送压力。
实现原理

数据库有个 binlog 二进制文件,记录了数据可执行的所有 SQL 语句。主从同步的目标就是把主数据库的 binlog 文件中的 SQL 语句复制到从数据库,让其在从数据的 relaylog 文件中再执行一次这些 SQL 语句即可。

异步复制和半同步

异步复制:MySQL 默认的主从复制方式就是异步复制,因为 Master 根本不考虑数据是否达到了 Slave,或 Slave 是否成功执行。
半同步:一主一从,一主多从情况下,Master 节点只要确认至少有一个 Slave 接受到了事务,即可向发起请求的客户端返回执行成功的操作。同时 Master 是不需要等待 Slave 成功执行完这个事务,Slave 节点接受到这个事务,并成功写入到本地 relay 日志中就算成功。

常见问题及其解决

主机宕机后,数据可能丢失:使用半同步复制,确保事务提交后至少传输到一个从库
从库只有一个sql Thread,主库写压力大,复制很可能延时:从库多线程apply binlog,解决从库复制延迟的问题。

杂项

分库分表

当单表的数据量达到1000W或100G以后,优化索引、添加从库等可能对数据库性能提升效果不明显,此时就要考虑对其进行切分了。切分的目的就在于减少数据库的负担,缩短查询的时间。

数据切分可以分为两种方式:垂直划分和水平划分。

垂直划分:

垂直划分数据库是根据业务进行划分,例如购物场景,可以将库中涉及商品、订单、用户的表分别划分出成一个库,通过降低单库的大小来提高性能。同样的,分表的情况就是将一个大表根据业务功能拆分成一个个子表,例如商品基本信息和商品描述,商品基本信息一般会展示在商品列表,商品描述在商品详情页,可以将商品基本信息和商品描述拆分成两张表。
水平划分:
水平划分是根据一定规则,例如时间或id序列值等进行数据的拆分。比如根据年份来拆分不同的数据库。每个数据库结构一致,但是数据得以拆分,从而提升性能。

猜你喜欢

转载自blog.csdn.net/m0_50816320/article/details/129299282