数据库面试题

文章目录

      • 基础知识
        • mysql有哪些基本的数据类型
        • 数据库的三大范式
        • 1.MySQL中InnoDB和MyISAM与的区别
        • 2.MySQL中varchar与char的区别
        • MySQL中的主键有什么作用
        • MySQL外键有什么作用
        • MySQL中的datetime和timestamp有什么区别
        • 什么是多表查询
      • 事务
        • 什么是事务,使用场景是什么
        • 事务的四大特性(ACID)是什么
        • 事务实现原理
        • 使用事务的场景有哪些
        • 什么是脏读、幻读、不可重复读
        • 数据库的隔离级别
        • 数据库的锁
      • 索引
        • 什么是索引,优缺点是什么
        • 什么地方会使用到索引
        • 索引有哪些类型
        • 主键索引和唯一索引的区别
        • 索引有什么数据结构
        • 创建索引有哪些原则
        • 什么是覆盖索引
        • 为什么要使用联合索引,而不是创建单独的两个索引
        • 删除一张表中的大量数据
        • 什么是聚簇索引和非聚簇索引
        • 非聚簇索引一定会回表查询吗
        • 什么是前缀索引
        • 什么是最左前缀匹配原则
        • 什么是联合索引
        • 是不是加了索引就一定会加快查询速度
        • B+树的时间复杂度是多少
      • 其他
        • 除了索引,还有哪些可以提高检索效率的方法?
      • mongodb
        • 关系型数据库和非关系型数据库之间的对比
        • 为什么mongodb使用B树
        • mongodb的存储引擎
        • mongodb中的索引
        • mongodb怎么实现事务
        • 为什么你项目的数据库会选择mongodb
        • mongodb和mysql都适合什么样的场景
        • 你处理的数据量有多大
        • 你有没有对你的数据库做什么优化

基础知识

mysql有哪些基本的数据类型

整型:tinyint(1字节),smallint(2字节),mediumint(3字节),int(4字节)
浮点数:float(4字节),double(8字节),decimal(16字节)
float和double使用二进制存储数据,decimal使用字符串存储数字
decimal可以100%精确表达一个数字,可以用在金融服务行业

数据库的三大范式

第一范式:列的原子性,每个列都不可以再拆分。

例如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。
数据库面试题_第1张图片

第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分(即存在联合主键时,要完全依赖于联合主键)。

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

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

1.MySQL中InnoDB和MyISAM与的区别

  1. InnoDB支持事务,MyISAM不支持
  2. InnoDB支持外键,MyISAM不支持
  3. InnoDB支持行级锁和表级锁(默认行级锁),MyISAM支持表级锁
  4. InnoDB支持MVCC,MyISAM不支持
  5. 全文索引的默认最小搜索长度不一样,

2.MySQL中varchar与char的区别

char长度是固定的,处理速度快,比较费空间
varchar长度是不固定的,处理速度慢,比较节省空间

char(M)每个值都占用M个字节,如果某个长度小于M,MySQL就会在它的右边用空格字符补足。在varchar(M)每个值只占用刚好够用的字节再加上一个用来记录其长度的字节(即总长度为L+1字节)。

myisam 存储引擎 建议使用固定长度,数据列代替可变长度的数据列。
memory存储引擎 目前都使用固定数据行存储,因此无论使用char varchar列都没关系,
innodb 存储引擎 建意使用varchar 类型

MySQL中的主键有什么作用

主键可以唯一地标识一行
主键是可以被外键有效引用的对象

MySQL外键有什么作用

保持数据的一致性

主表的外键可以有多个,子表必须把外键当做主键。
例如现在有两张表,一张学生信息表,一张学生成绩表;把学生信息表中的学号字段设为外键,连接成绩表中的学号字段,则成绩表中的学号字段要设为主键。

MySQL中的datetime和timestamp有什么区别

  • datetime时间范围是1001-9999,timestamp时间范围是1970-2038
  • datetime存储的时间与时区无关,timestamp存储的时间与时区有关,修改时区时timestamp的时间也会改变(例如存进数据库的时间是北京时间下午一点,将时区改为东九区后时间会变为下午两点)
  • datetime占8字节,timestamp占4字节
  • datetime默认值是null,timestamp默认值是当前时间

什么是多表查询

就是一次select多张表的数据
union all

事务

什么是事务,使用场景是什么

是一个不可分割的数据库操作序列
执行的结果是将数据库从一种一致性状态变到另一种一致性状态

使用场景:买票、转账

事务的四大特性(ACID)是什么

A(Atomicity)—原子性
事务里面的东西要么全部都做,要么全不不做

C(Consistency )—一致性
做完一个事务后,会将数据库从一个一致性状态转换到另一个一致性状态。
主要指数据库从一个正确的状态转换到另外一个正确的状态,操作过程是合法的,不会违反我们给数据库定义的一些规则。
例如银行的数据库,客户的账户余额不能是负值;int型字段不能赋予一个字符串等。

I( Isolation)—隔离性
各个事务事件之间相互隔离,不互相影响

D(Durability)—持久性
持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

事务实现原理

事务是通过重做日志、回滚日志和锁来实现的。
事务的ACD是通过redo log和undo log来实现的(重做日志和回滚日志)。隔离性是通过锁来实现的。

Undo Log
实现事务的原子性。

undo log就是帮助实现undo(回滚)操作的日志。
undo log记录了sql执行的相关信息,需要回滚的时候回执行sql语句相反的操作:对于每个insert,回滚时会执行delete;对于每个delete,回滚时会执行insert;对于每个update,回滚时会执行一个相反的update,把数据改回去。

Redo Log
实现事务的持久性。redo log用于crash recovery,保证MySQL宕机也不会影响持久性。

redo log存在的背景:
数据库的数据一般是存在磁盘的,但磁盘IO很慢,所以一般会在缓存池(buffer pool)里面进行读写,再定期将缓存池中的数据刷新到磁盘(这个过程称为刷脏)。读写的过程中如果mysql宕机就会导致数据丢失,失去"持久性"。

为了解决这个问题,修改数据时会先在redo log中记录下操作,再修改缓存池中的数据,事务提交的时候会持久化redo log的数据。如果mysql宕机,重启时可以读取redo log中的数据,对数据库进行恢复。

既然redo log也需要在事务提交时将日志写入磁盘,为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:

(1)刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。

(2)刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分,无效IO大大减少。

使用事务的场景有哪些

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

脏读(读取了未提交的数据):一个事务已经更新一份数据,另外一个事务在读取同一份数据,如果第一个事务回滚了,那第二个事务读到的数据就是错误的。

不可重复读(前后读取的结果不一样):一个事务两次查询的结果不一样。

解决方式:使用行级锁,一个事务修改一条数据的时候锁定这行数据,修改完再解锁。

幻读(前后多次读取,数据总量不一致):一个事务读了几行数据,另外一个事务插入了几行数据,那第一个事务在后面的查询过程中会发现有几列数据是它之前没查到的。

解决方式:使用表级锁,添加或者删除完数据后再解锁。

幻读和不可重复读有什么区别:

幻读是读取了其他事务新增或删除的数据,针对insert和delete操作
不可重复读是读取了其他事务修改的数据,针对update操作

数据库的隔离级别

数据库面试题_第2张图片
数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable。

Read uncommitted:
一个事务可以读到其他事务还没有提交的数据
会造成脏读

Read committed:
一个事务在执行过程中,读到其他事务已经提交的数据,造成前后的查询数据不一致的问题。
解决了脏读的问题,会造成不可重复读。

“不可重复"指的是"查询的结果不可重复”,事务希望相同的两次查询,查询结果应该是重复的,但是结果查下来是不可重复的。

Repeatable read:
这个等级下,事务可以实现重复读。即一个事务在执行的过程,查询到的数据内容是保持一致的。
这个等级解决了不可重复读的问题,但是会出现幻读的问题。

Serializable:
是最高的事务隔离级别,在该级别下,事务之间完全不干扰,但是代价很高,性能很低。

这个等级解决了脏读、不可重复读、幻读的问题。

隔离级别 含义 会造成的问题 默认隔离级别数据库
Read uncommitted 一个事务可以读其他事务还没有提交的数据 脏读
Read committed 一个事务可以读其他事务提交后的数据 会造成不可重复读 Oracle,SQL Server
Repeatable read 事务可以实现可重复读 会造成幻读 MySQL
Serializable 事务之间完全不会相互影响

数据库的锁

行级锁
共享锁

索引

什么是索引,优缺点是什么

索引:目录,文件查找的结构

优点:

  • 加大检索速度

缺点:

  • 创建、维护索引会花时间,降低了增改删的效率
  • 会占用物理空间

什么地方会使用到索引

where添加条件时:
数据库面试题_第3张图片
上图中,根据id查询记录,因为id字段仅建立了主键索引,因此此SQL执行可选的索引只有主键索引,如果有多个,最终会选一个较优的作为检索的依据

-- 增加一个没有建立索引的字段
alter table innodb1 add sex char(1);
-- 按sex检索时可选的索引为null
EXPLAIN SELECT * from innodb1 where sex='男';

数据库面试题_第4张图片
order by
对某个字段进行排序的时候,如果该字段没有索引的话,会对数据进行外部排序(将数据从硬盘读取到内存使用内部排序,最后合并排序结果)。这个过程会比较耗时,首要要从存储设备里面读取数据,还要对数据进行排序。

join
join语句匹配关系(on)涉及的字段建立索引能够提高效率

索引有哪些类型

可以分为主键索引,唯一索引,普通索引,全文索引

主键索引:
主键约束,唯一标识数据库中的每条记录
必须包含唯一的值
不能包含NULL值
每个表都必须有且仅有一个主键

唯一索引:
唯一索引的目的不是为了提高访问速度,只是为了避免数据出现重复


主键索引和唯一索引的区别

主键索引不允许有null值,唯一索引可以有;
一个表只能有一个主键,可以有多个唯一索引;

索引有什么数据结构

有哈希表,有序数组,N叉树;

InnoDB里面是B+树。

为什么使用B+树:

  • B+ 树节点只有索引的功能,节点比较小,空间利用率更高,单次查询磁盘访问次数比较少,查询效率高
  • 所有的数据都包含在叶子节点里面,非叶子节点只做索引的功能,查询性能比较稳定
  • 叶子节点都用指针连在一起,形成有序链表,范围查找比较方便

B和B+树的对比:

B树的节点里面同时存键和值,B+树只有叶子节点存放数据(比如如果是非主键索引里面的节点存放的数据就是主键的值)。

对于B树来说,把频繁访问的数据放在靠近根节点的地方将会大大提高热点数据的查询效率。这种特性使得B树在特定数据重复多次查询的场景中更加高效。

对于B+树来说,叶子节点只保存索引,所以一次读取可以从页数据里面获得更多的键,可以更快地缩小查找范围;同时因为数据只在叶子节点,所以查询性能会比较稳定;而且所有的叶子节点都通过链表连接,所以范围查询和排序的时候有很大的优势。

Hash表和B+树的对比:
Hash索引等值查询的时候速度比较快

B+树所有的数值内容都保存在叶子节点,查询性能比较稳定;叶子节点通过指针链接在一起,范围查询、排序的时候很方便;

因为Hash函数的不可预测性,不支持多列索引的最左前缀匹配
Hash肯定需要回表,B+树在主键索引,覆盖索引的时候可以不用回表

创建索引有哪些原则

  • 查询频繁的字段适合建立索引;经常排序、分组的字段适合建立索引
  • 更新频繁的字段不适合建立索引;
  • 尽量考虑创建联合索引(可以过滤筛选的数据更多)

什么是覆盖索引

要查的列就是索引里面的列。在覆盖索引的条件下,就不用查主键索引,直接从非主键索引中就能查到记录。避免回表耗费时间。

例如创建了索引(field1, field2, field3),然后select field3 from table_name where field1=2, field2=3 这个查询就不会行使回表操作,直接返回结果。


为什么要使用联合索引,而不是创建单独的两个索引

  • 因为MySQL一次查询只能使用一个索引,而不是使用两条索引起到叠加的效果
  • 联合索引可以实现索引覆盖
  • 可以过滤筛选的数据更多

删除一张表中的大量数据

如果一张表里面有很多数据,我需要删除的量在百万以上,应该怎么删除这些数据?

应该先删除索引,再删除需要删除的数据,再把索引加回来。
因为索引文件是单独存在的,增删改的操作都会产生对索引文件的操作,这些操作可能会对磁盘有额外的IO,降低增删改的效率。删除数据的速率和创建的索引数量是成正比的。

所以如果需要删除一张表里面大量的数据的时候,应该先删除里面的索引,再删除数据,最后再把索引加回来。

什么是聚簇索引和非聚簇索引

聚簇索引就是数据行记录和索引放到一起,InnoDB里面只有主键索引是聚簇索引。使用聚簇索引来查数据的时候,可以不用回表。

一张表只能有一个聚簇索引,因为一张表的数据只有一种存储方式。

非聚簇索引就是索引的结果是主键的值,需要做回表的操作。
非聚簇索引也叫二级索引、辅助索引

非聚簇索引一定会回表查询吗

不一定,可以有覆盖索引

什么是前缀索引

使用字段的前几个字符建立索引。
用于密码匹配、文字匹配等场景。
(建立索引的时候,默认是使用字段的全部内容)

前缀索引的创建难度在于到底选择多长的前缀以及字段的选取方式。

可以利用select count(*)/count(distinct left(password,prefixLen));,通过从调整prefixLen的值(从1自增)查看不同前缀长度的一个平均匹配度,接近1时就可以了(表示一个密码的前prefixLen个字符几乎能确定唯一一条记录)

什么是最左前缀匹配原则

最左前缀匹配原则用于多列索引的情况,如果索引条件没有覆盖索引的最左前缀,那就不会用到这个索引。

例如创建了(c1, c2, c3)的索引,那(c2, c3, c2+c3)的查询条件是用不了索引的。

mysql会在条件里面一直向右匹配,匹配到范围查询为止。如果将精确查询放到范围查询的后面,该精确查询的索引就用不到了。

什么是联合索引

使用多个字段创建的索引是联合索引,联合索引中,如果想要命中索引要按照建立索引时的字段顺序挨个使用,否则无法命中索引。

因为索引会按照创建索引时的字段顺序来对数据进行排序。

一般情况下,将查询需求比较强的字段放在前面。

是不是加了索引就一定会加快查询速度

不一定,如果查询的数据范围很大,例如最终的查询结果可能占了整体数据的80,那还是不加索引比较好,不然加载索引再回表的时间也很长

B+树的时间复杂度是多少

B+树,假设数据量为n,一个节点假设它有m个子节点,树高就是log(m)n,每一层平均遍历m/2个节点,时间复杂度是(m/2)*log(m)n

这篇文档

其他

除了索引,还有哪些可以提高检索效率的方法?

mongodb

关系型数据库和非关系型数据库之间的对比

关系型数据库:
非关系型数据库:not only sql,数据之间的关联比较少,更容易分散存储

为什么mongodb使用B树

因为mongodb的文档存储结构是json,mongodb是聚合型的数据库,一般就想要通过key得到value,而B树的结构就是每个节点都有Data域,比较符合mongodb的数据库特性。

mongodb的存储引擎

wiredtiger:
支持document级别的锁
因此多个客户端可以同时更新一个colleciton中的不同document
支持MVCC

mmap:
支持到collection级别的锁

mongodb中的索引

mongodb中有单字段索引、复合索引、多key索引、文本索引、唯一索引、TTL索引、稀疏索引。
普通索引和稀疏索引的区别是,普通索引对于不在该字段的documents会假定该documents的索引字段为null
而稀疏索引则会直接跳过该document,效率更高。

mongodb中没有聚簇索引的概念,数据和索引是单独分离的。

mongodb怎么实现事务

在Nosql中没有事务这个概念,每一个数据集都是原子级别的。

为什么你项目的数据库会选择mongodb

存储的优势:
有很多内嵌文档的形式,比如一个区域下有很多项目,项目下有不同的实例类型,不同实例类型有不同维度的数据,希望以比较直观的方式看到数据,而不是join很多表。mongodb 的文档都是json结构,比较符合需求,可以直接提取想要的数据

字段自由,方便后期扩展新的字段

操作优势:
核心需求是读表,不需要写或者修改,对数据的处理不需要有很高的事务性,一般存进去的数据就是比较直接的需求数据,不用再做更深的操作;

拓展优势:
后期数据量巨大,且数据之间没有强关联性,方便拓展,方便横向拓展

mongodb和mysql都适合什么样的场景

你处理的数据量有多大

1000多万行的数据,上万GB

你有没有对你的数据库做什么优化

加了索引

你可能感兴趣的:(MySQL)