面试相关-数据库Mysql

Posted 尚墨1111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试相关-数据库Mysql相关的知识,希望对你有一定的参考价值。

1.基本知识

1.1 数据库三大范式是什么

第一范式:每个列都不可以再拆分。
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

1.2 mysql的基本数据类型

  |-- 基本数据类型
    |-- 数字
        int、tinyInt、smallint、mediumint
        float、double、decimal
    |-- 字符
        char
        varchar(n):定长字符串
        text:长文本
    |-- 日期
        date:年月日
        time:时分秒
        datetime:年月日时分秒
        timestamp:时间戳

1.3 为什么要用存储过程,存储过程的优缺点

存储过程概念

存储过程是一些sql语句和控制语句组成的被封装起来的过程,它驻留在数据库中,可以被客户应用程序通过存储过程名字调用,也可以从另一个存储过程或触发器调用。

为什么要用存储过程?

(1)执行速度快——存储过程只在创建时进行编译,以后每次执行存储过程都不需要重新编译,而一般SQL语句没执行一次就需编译一次,所以使用存储过程可提高数据库的执行速度。

(2)减少网络通信量——当对数据库进行复杂操作时,(如对多个表进行insert、update、select、delete时)可将这些复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序完成就是多条SQL语句,可能要多次连接数据库,而换成存储过程只需一次连接。

存储过程的缺点

(1)开发调试差、可移植性差、重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译
(2)如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

1.4 说一说drop、delete与truncate的区别

SQL中的drop、delete、truncate都表示删除,但是三者有一些差别

delete和truncate只删除表的数据不删除表的结构

 |--- 比较delete和truncate
     delete 删除可以撤销,删除某个内容
            DELETE FROM infor WHERE subjects = '小米';
            ROLLBACK;
     truncate 删除不可撤销,删除所有内容

drop、delete与truncate分别在什么场景之下使用?

不再需要一张表的时候,用drop
删除部分数据行时候,用delete,并且带上where子句
保留表而删除所有数据的时候用truncate

1.5 一条sql语句在mysql中如何执行

MySQL 基本架构概览:Server 层 +存储引擎层:

  • Server 层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog 日志模块。
  • 存储引擎主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎
    在这里插入图片描述

连接器: 身份认证和权限相关(登录 MySQL 的时候)。
查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)
分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
优化器:
按照 MySQL 认为最优的方案去执行。
执行器: 执行语句,然后从存储引擎返回数据

1.6 数据库存储时间

在这里插入图片描述

  • 不要用字符串存储日期,字符串占用的空间更大,效率比较低(逐个字符进行比对),无法用日期相关的 API 进行计算和比较
  • DateTime 类型是没有时区信息的
  • Timestamp 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间
  • int 或者 bigint 类型的数值也就是时间戳来表示时间,可读性太差了,无法直观的看到具体时间

2. 存储引擎

2.1 Mysql有哪些存储引擎,默认的存储引擎是什么?

一共9种
存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。MySql数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎

MySQL 当前默认的存储引擎是 InnoDB,并且在 5.7 版本所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务

mysql> show engines;

在这里插入图片描述

Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。

MyIASM引擎(原本Mysql的默认引擎):不提供事务的支持,也不支持行级锁和外键。

MEMORY引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。

2.2 MyISAM 和 InnoDB 的区别

1.是否支持行级锁。MyISAM 只有表级锁,一锁就是锁住了整张表,而 InnoDB 支持行级锁和表级锁,默认为行级锁。

2.是否支持事务。MyISAM 不提供事务支持。InnoDB 提供事务支持,具有提交(commit)和回滚(rollback)事务的能力。

3.是否支持外键,MyISAM 不支持,而 InnoDB 支持。
4.是否支持数据库异常崩溃后的安全恢复
使用 InnoDB 的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log
5.是否支持 MVCC,MyISAM 不支持,而 InnoDB 支持。

表级锁和行级锁对比:

表级锁: MySQL 中锁定 粒度最大 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。

行级锁: MySQL 中锁定 粒度最小 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

啥叫外键:

关系型数据库中的一条记录中有若干个属性,若其中某一个属性组能唯一标识一条记录,该属性组就是主键,学生表(学号,姓名,性别,班级) 中的学号,成绩表中的学号不是成绩表的主键,但它和学生表中的学号相对应,并且学生表中的学号是学生表的主键,则称成绩表中的学号是学生表的外键
比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键

MySQL InnoDB 引擎

使用 redo log(重做日志) 保证事务的持久性
使用 undo log(回滚日志) 来保证事务的原子性
MySQL InnoDB 引擎通过 锁机制、MVCC 等手段来保证事务的隔离性
保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。

MVCC

可以看作是行级锁的一个升级,可以有效减少加锁操作,提供性能。MVCC叫多版本并发控制,即多个不同版本的数据实现并发控制的技术,其基本思想是为每次事务生成一个新版本的数据在读数据时选择不同版本的数据即可以实现对事务结果的完整性读取

2.3 InnoDB与MyISAM各自的优势是什么,能用在什么场合

大多数时候我们使用的都是 InnoDB 存储引擎,在某些读密集的情况下,使用 MyISAM 也是合适的。不过,前提是你的项目不介意 MyISAM 不支持事务、崩溃恢复等缺点

量读,几乎没有写请求 和 小于5.6.4版本需要全文索引,选择 MyISAM,其他情况选择InnoDB。MyISAM 的性能还行,各种特性也还不错(比如全文索引、压缩、空间函数等


3. 事务

在这里插入图片描述

3.1 何为 ACID 特性呢?

原子性(Atomicity) : 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
一致性(Consistency): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性(Durabilily): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

3.2 并发事务带来哪些问题?

脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,依据“脏数据”所做的操作可能是不正确的。

丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改

不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

幻读(Phantom read): 它发生在一个事务读取了几行数据,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

不可重复读和幻读区别:

不可重复读的重点是修改,比如多次读取一条记录发现其中某些列的值被修改。
幻读的重点在于新增或者删除比如多次读取一条记录发现记录增多或减少了。

3.3 事务隔离级别有哪些?

在这里插入图片描述

READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

SERIALIZABLE(可串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。


MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。
隔离级别越低,事务请求的锁越少,大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容)
nnoDB 存储引擎在 分布式事务 的情况下一般会用到 SERIALIZABLE(可串行化) 隔离级别

4.索引

4.1 索引是什么?

索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树, B+树和 Hash。

相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。

4.2 索引有哪些优缺点?

优点 :

  • 使用索引可以大大加快数据的检索速度(大大减少的检索的数据量), 这也是创建索引的最主要的原因。
  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性

大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,那么使用索引也不一定能够带来很大提升

缺点:

  • 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
  • 空间方面:索引需要占物理空间。

4.3 为什么MySQL 没有使用Hash作为索引的数据结构呢?

1.Hash 冲突问题 :我们上面也提到过Hash 冲突了,不过对于数据库来说这还不算最大的缺点。
2.Hash 索引不支持顺序和范围查询。是它最大的缺点: 假如我们要对表中的数据进行排序或者进行范围查询,那 Hash 索引可就不行了。

4.4 索引的底层数据结构

4.4.1 各种树

二叉搜索树:左子节点< 父节点< 右子节点
在这里插入图片描述

若想二叉树的查询效率尽可能高,需要这棵二叉树是平衡的
**

② 平衡二叉树:左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
在这里插入图片描述

平衡二叉树每一层最多容纳的结点数量为2^(n-1),有限,当数据太多时不够用,层数多之后IO来回的次数多,所以无法满足实际需求,基于此又延伸出B树

③ B-Tree:平衡多路查找树,也叫B树。

每个结点都可能包含多个元素,并且非叶子结点在元素的左右都有指向子结点的指针。查询所经过的结点数量要少很多,也就意味着要少很多次的磁盘IO,这对性能的提升是很大的。

一棵 m 阶B-tree的特性


m 阶的定义:一个节点能拥有的最大子节点数来表示这颗树的阶数
举个例子:
如果一个节点最多有 n 个key,那么这个节点最多就会有 n+1 个子节点,这棵树就叫做 n+1(m=n+1)阶树

在这里插入图片描述
3阶B-tree示意图
在这里插入图片描述
实际磁盘举例:
在这里插入图片描述


④ B+Tree中,非叶子节点上只存储key值信息,每个节点存储的key值数量增加,降低B+Tree的高度
在这里插入图片描述
一颗m阶的B+树和m阶的B树的差异在于:
在这里插入图片描述

1.非叶子结点的子树指针与关键字个数相同
2.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间)
3.为所有叶子结点增加一个链指针。图中Q是通过指针连在一起的。
4.所有关键字都在叶子结点出现。叶子结点相当于是存储(关键字)数据的数据层
5.B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中)
6.所有的非终端结点可以看成是索引部分,结点中的关键字是有其孩子指向的子树中最大(或最小)关键字。

B 树& B+树两者有何异同呢?

① B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key
② B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点
③ B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。

4.4.2 B+树在存储引擎中的实现及区别

① B+树在MyISAM索引实现

叶节点的data域存放的是数据记录的地址,MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分

在这里插入图片描述
② B+树在InnoDB索引实现
在这里插入图片描述
区别:

第一个重大区别是InnoDB的数据文件本身就是索引文件
MyISAM索引文件仅保存数据记录的地址。
而在InnoDB中data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
在这里插入图片描述

第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。例如用名字来作为辅助索引。data中存的是主键

在这里插入图片描述

聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

在这里插入图片描述

4.5 索引类型

主键索引:一张数据表有只能有一个主键,并且主键不能为 null,不能重复。

二级索引(辅助索引):二级索引的叶子节点存储的数据是主键。也就是说,通过二级索引,可以定位主键的位置。
唯一索引,普通索引,前缀索引等索引属于二级索引

唯一索引(Unique Key) :唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL,一张表允许创建多个唯一索引。 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。

普通索引(Index)普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。

前缀索引(Prefix) :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。

全文索引(Full Text) :全文索引主要是为了检索大文本数据中的关键字的信息,是目前搜索引擎数据库使用的一种技术。Mysql5.6 之前只有 MYISAM 引擎支持全文索引,5.6 之后 InnoDB 也支持了全文索引。

4.7 聚集索引:即索引结构和数据一起存放的索引。

叶节点包含了完整的数据记录,这种索引方式叫聚集索引
因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键,如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

聚集索引的优点

聚集索引的查询速度非常的快,因为整个 B+树本身就是一颗多叉平衡树,叶子节点也都是有序的**,定位到索引的节点,就相当于定位到了数据**。

聚集索引的缺点

① 依赖于有序的数据 :因为 B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。
② 更新代价大 : 如果对索引列的数据被修改时,那么对应的索引也将会被修改, 而且况聚集索引的叶子节点还存放着数据,修改代价肯定是较大的, 所以对于主键索引来说,主键一般都是不可被修改的。

非聚集索引的优点

更新代价比聚集索引要小 。非聚集索引的更新代价就没有聚集索引那么大了,非聚集索引的叶子节点是不存放数据的

非聚集索引的缺点

① 跟聚集索引一样,非聚集索引也依赖于有序的数据
可能会二次查询(回表) :这应该是非聚集索引最大的缺点了。 当查到索引对应的指针或主键后,可能还需要根据指针或主键再到数据文件或表中查询。

覆盖索引

即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了, 而无需回表查询。

如主键索引,如果一条 SQL 需要查询主键,那么正好根据主键索引就可以查到主键
再如普通索引,如果一条 SQL 需要查询 name,name 字段正好有索引, 那么直接根据这个索引就可以查到数据,也无需回表

在这里插入图片描述

4.8 创建索引的注意事项

① 不为 NULL 的字段 :索引字段的数据应该尽量不为 NULL,因为对于数据为 NULL 的字段,数据库较难优化。
② 被频繁查询的字段 :我们创建索引的字段应该是查询操作非常频繁的字段
③ 被频繁更新的字段:应该慎重建立索引
④ 注意避免冗余索引
⑤ 在使用 InnoDB 时使用与业务无关的自增主键作为主键,即使用逻辑主键,而不要使用业务主键。
⑥在使用 limit offset 查询缓慢时,可以借助索引来提高性能

4.8.1 分页:查第1页和查第10000页有什么区别。

直接用limit 分页语句

select * from product limit 10, 20   0.016秒
select * from product limit 100, 20   0.016秒
select * from product limit 1000, 20   0.047秒
select * from product limit 10000, 20   0.094秒
select * from product limit 400000, 20   3.229秒
select * from product limit 866613, 20   37.44

1)limit语句的查询时间与起始记录的位置成正比
2)mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用

解决办法:

1.加上索引排序
select * from table order by xx,id(任意有索引的字段) limit 0,10

4.9 MySQL 如何为表字段添加索引

在这里插入图片描述

4.10 百万级别或以上的数据如何删除

关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,删除数据的速度和创建的索引数量是成正比的

  • 先删除索引(此时大概耗时三分多钟) 然后删除其中无用数据(此过程需要不到两分钟)
  • 删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。

致谢:

BTree和B+Tree
JavaGuide

以上是关于面试相关-数据库Mysql的主要内容,如果未能解决你的问题,请参考以下文章

面向面试编程代码片段之GC

面试相关-数据库Mysql

Java面试 —— MySQL相关

Java面试 —— MySQL相关

MySQL面试高频100问

MySQL面试高频100问