面试准备:数据库常见面试题汇总

1.简单解释数据库三范式?

第一范式就是数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值。

第二范式要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体

第三范式要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。

更多知识点,参考:高性能Mysql——范式与反范式

2.不满足数据库三范式可能会出现什么情况?

数据冗余(想修改一个属性,就要更新多行数据)
插入异常(想要插入数据,结构因为表设计的问题,导致不能成功插入)
删除异常(只想删除其中的某些数据 ,结果把不该删的也删了)
更新异常(想更新一条数据,结果工作量大,还容易出错)

3.解释脏读、不可重复读,幻读,更新丢失


  • 脏读(Dirty read):在一个事务中读取到另一个事务已经修改但没有提交的数据。

例如,事务A对数据进行了修改,但是还没有提交,这时事务B读取这个数据,然后事务A回滚,那么事务B取的数据无效。不符合一致性

解决办法:把数据库的事务隔离级别调整到READ_COMMITTED


  • 不可重复读(NonRepeatable Read):不能读到相同的数据内容,事务A读取到了事务B已经提交的修改数据(即一个事务范围内两个相同的查询却返回了不同数据)。

例如事务A先读取数据,然后事务B对该同一数据修改并提交,那么事务A再次读取该数据时,由于事务B对该数据的修改,事务A两次读到的的数据可能是不一样的。不符合隔离性

解决办法:把数据库的事务隔离级别调整到REPEATABLE_READ


  • 幻读(Phantom Read):事务在插入已经检查过不存在的记录时,惊奇的发现这些数据已经存在了(针对的insert操作) 。

在事务A查询结束后,事务B往User表中插入了一条id为1的数据。此时,由于事务A查询到id为1的用户不存在,因此插入1条id为1的数据,报错:主键冲突。不符合隔离性。

解决办法:把数据库的事务隔离级别调整到SERIALIZABLE_READ


  • 更新丢失(Update lose):两个事务同时操作相同数据,后提交的事务会覆盖先提交的事务处理结果。

解决办法:乐观锁

4. Mysql提供了哪几种事务隔离级别?

MySQL数据的四种隔离级别:
  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
  ③ Read committed (读已提交):可避免脏读的发生。
  ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

通过SELECT @@transaction_isolation;(mysql 5.7以下是select @@tx_isolation)可以查看事务隔离级别:
在这里插入图片描述

隔离界别为可重复读,那么我写一个脏读和可重复读的事务:

# 事务A
begin;
	select * from orders where id="190827F4AK12R30H";
commit;
# 事务B
begin;
	UPDATE orders SET left_msg="new message" where id="190827F4AK12R30H";
	select sleep(10);
commit;

查询结果是:尽管事务B修改了left_msg为new message,但是事务A的查询结果是old message。

# 事务A
begin;
	select * from orders where id="190827F4AK12R30H";
	select sleep(10);
	select * from orders where id="190827F4AK12R30H";
commit;

# 事务B
begin;
	UPDATE orders SET left_msg="new message" where id="190827F4AK12R30H";
commit;

查询结果是:尽管事务B修改了left_msg为new message,但是两次事务A的查询结果都是 old message。

最后试试幻读:

# 事务A
begin;
	select * from stu where id=1;
	select sleep(10);
	insert into stu(id,name,age) values (1,"xiaoming",13);
commit;
# 事务B
begin;
	insert into stu(id,name,age) values (1,"xiaohong",15);
commit;

运行结果:
在这里插入图片描述
可把事务级别改成串行set session transaction isolation level SERIALIZABLE;
使用set session transaction isolation level REPEATABLE READ;改回来

5.MySQL中varchar与char的区别?

CHAR和VARCHAR最大的不同就是一个是固定长度,一个是可变长度。
CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义 char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充(并且如果存储的char类型的字符串后面有空格的话,innodb会忽略)。
VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则 使用两个字节)。

一般来说,CHAR比VARCHAR更快,因为CHAR是固定长度的,而VARCHAR需要增加一个长度标识,处理时需要多一次运算。但是有例外,参考:MySQL Innodb数据库性能实践——VARCHAR vs CHAR,但是如果使用的是Innodb引擎的话,推荐使用varchar代替char。特别是字符串的平均长度比最大长度要小很多的情况;当然,如果你的字符串本来就很短或者字符串长度固定,例如只有10个字符,那么就优先选CHAR了。

6.MySQL中int(11)与int(3)的区别?

当我们在选择使用int的类型的时候,不论是int(3)还是int(11),它在数据库里面存储的都是4个字节的长度。

如果int的值为10
int(11)显示结果为00000000010
int(3)显示结果为010
就是显示的长度不一样而已,但都是占用四个字节的空间。

类型长度,参考:https://www.runoob.com/mysql/mysql-data-types.html。

更多知识点,参考高性能Mysql——Schema与数据类型优化

7.date,datetime和timestamp数据类型有什么区别?

一个完整的日期格式如下:YYYY-MM-DD HH:MM:SS[.fraction],它可分为两部分:date部分和time部分,其中,date部分对应格式中的“YYYY-MM-DD”,time部分对应格式中的“HH:MM:SS[.fraction]”。对于date字段来说,它只支持date部分,如果插入了time部分的内容,它会丢弃掉该部分的内容,并提示一个warning。

timestamp和datetime的不同点:
DATETIME 的日期范围是 1001——9999 年;TIMESTAMP 的时间范围是 1970——2038 年
DATETIME 存储时间与时区无关;TIMESTAMP 存储时间与时区有关,显示的值也依赖于时区
DATETIME 的存储空间为 8 字节;TIMESTAMP 的存储空间为 4 字节
DATETIME 的默认值为 null;TIMESTAMP 的字段默认不为空(not null),默认值为当前时间(CURRENT_TIMESTAMP)

8.union 与union all的区别

union 在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排 序运算,删除重复的记录再返回结果。 union all 则会显示重复结果,只是简单的两个结果合并并返回.所以效率比union高,在保证没有重复数据的情况下用union all.

9.各种join的区别?

参考:https://blog.csdn.net/weter_drop/article/details/84729822

10.drop,delete与truncate的区别?

  • DROP语句:
    直接删掉表。drop语句将表所占用的空间全释放掉。
  • TRUNCATE语句:
    删除表中数据,再插入时自增长id又从1开始 。当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小。 并且不会把单独的删除操作记录记入日志保存,删除行是不能恢复的。
  • DELETE语句:
    删除表中数据,可以加where字句,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。DELETE操作不会减少表或索引所占用的空间。

delete语句为DML(data maintain Language),这个操作会被放到 rollback segment中,事务提交后才生效。如果有相应的 tigger,执行的时候将被触发。
truncate、drop是DLL(data define language),操作立即生效,原数据不放到 rollback segment中,不能回滚。

11.MySQL有哪几种索引?

参考:高性能Mysql——创建高性能的索引

参考:http://www.k6k4.com/simple_question/qshow/aaqgsagdh1539184953117。

12.简要说明InnoDB事务是如何通过日志来实现的?

日志分为redo和undo。


  • redo log叫做重做日志,是用来实现事务的持久性(用于数据库的崩溃恢复)。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中。

比如下面的操作,从银行卡账户转账到理财账户表:
在这里插入图片描述
在这里插入图片描述

mysql 为了提升性能不会把每次的修改都实时同步到磁盘,而是会先存到Boffer Pool(缓冲池)里头,把这个当作缓存来用。然后使用后台线程去做缓冲池和磁盘之间的同步。

那么问题来了,**如果还没来的同步的时候宕机或断电了怎么办?**还没来得及执行上面图中红色的操作。这样会导致丢部分已提交事务的修改信息!所以引入了redo log来记录已成功提交事务的修改信息,并且会把redo log持久化到磁盘,系统重启之后在读取redo log恢复最新数据。


  • undo log 叫做回滚日志,用于记录数据被修改前的信息。他正好跟前面所说的重做日志所记录的相反,重做日志记录数据被修改后的信息。undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。

在这里插入图片描述

undo log 记录事务修改之前版本的数据信息,因此假如由于系统错误或者rollback操作而回滚的话可以根据undo log的信息来进行回滚到没被修改前的状态。

事务的原子性是通过 undo log 来实现的
事务的持久性性是通过 redo log 来实现的
事务的隔离性是通过 (读写锁+MVCC)来实现的

13.简述Mysql Innodb引擎和MyIASM引擎的区别?

InnoDB

默认事务型引擎,被广泛使用的存储引擎
数据存储在共享表空间,即多个表和索引都存储在一个表空间中,可通过配置文件修改
主键查询的性能高于其他类型的存储引擎
内部做了很多优化,如:从磁盘读取数据时会自动构建hash索引,插入数据时自动构建插入缓冲区
通过一些机制和工具支持真正的热备份
支持崩溃后的安全恢复
支持行级锁
支持外键

MyISAM

拥有全文索引、压缩、空间函数
不支持事务和行级锁、不支持崩溃后的安全恢复
表存储在两个文件:MYD 和 MYI
设计简单,某些场景下性能很好,例如获取整个表有多少条数据,性能很高

14.sql执行慢的原因有哪些,如何进行sql优化?

一、导致SQL执行慢的原因

1、硬件问题。如网络速度慢,内存不足,I/O吞吐量小,磁盘空间满了等。

2、没有索引或者索引失效。(一般在互联网公司,DBA会在半夜把表锁了,重新建立一遍索引,因为当你删除某个数据的时候,索引的树结构就不完整了。所以互联网公司的数据做的是假删除,一是为了做数据分析,二是为了不破坏索引 )

3、数据过多(分库分表)

4、服务器调优及各个参数设置(调整my.cnf)

二、分析原因时,一定要找切入点

1、先观察,开启慢查询日志,设置相应的阈值(比如超过3秒就是慢SQL),在生产环境跑上个一天过后,看看哪些SQL比较慢。

2、Explain和慢SQL分析。比如SQL语句写的烂,索引没有或失效,关联查询太多(有时候是设计缺陷或者不得以的需求)等等。

3、Show Profile是比Explain更近一步的执行细节,可以查询到执行每一个SQL都干了什么事,这些事分别花了多少秒。

4、找DBA或者运维对MySQL进行服务器的参数调优。
解析:
(1)explain出来的各种item的意义

id:每个被独立执行的操作的标志,表示对象被操作的顺序。一般来说, id 值大,先被执行;如果 id 值相同,则顺序从上到下。
select_type:查询中每个 select 子句的类型。
table:名字,被操作的对象名称,通常的表名(或者别名),但是也有其他格式。
partitions:匹配的分区信息。
type:join 类型。
possible_keys:列出可能会用到的索引。
key:实际用到的索引。
key_len:用到的索引键的平均长度,单位为字节。
ref:表示本行被操作的对象的参照对象,可能是一个常量用 const 表示,也可能是其他表的
key 指向的对象,比如说驱动表的连接列。
rows:估计每次需要扫描的行数。
filtered:rows*filtered/100 表示该步骤最后得到的行数(估计值)。
extra:重要的补充信息。

(2)profile的意义以及使用场景

Profile 用来分析 sql 性能的消耗分布情况。当用 explain 无法解决慢 SQL 的时候,需要用profile 来对 sql 进行更细致的分析,找出 sql 所花的时间大部分消耗在哪个部分,确认 sql的性能瓶颈。

(3)explain 中的索引问题

Explain 结果中,一般来说,要看到尽量用 index(type 为 const、 ref 等, key 列有值),避免使用全表扫描(type 显式为 ALL)。比如说有 where 条件且选择性不错的列,需要建立索引。
被驱动表的连接列,也需要建立索引。被驱动表的连接列也可能会跟 where 条件列一起建立联合索引。当有排序或者 group by 的需求时,也可以考虑建立索引来达到直接排序和汇总的需求。

参考:高性能Mysql——创建高性能的索引

15.视图的作用,视图可以更改么?

视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。
视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by 则对视图再次order by将被覆盖。
创建视图:create view XXX as XXXXXXXXXXXXXX;
对于某些视图比如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。

16. 说一说MySQL中的锁机制

按粒度分:

  • 表级锁:粒度最大的一种锁,表示对当前操作的整张表加锁。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低
  • 行级锁:粒度最小的一种锁,表示只针对当前操作的行进行加锁。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高
  • 页级锁:粒度介于行级锁和表级锁中间的一种锁。开销、加锁时间和并发度界于表锁和行锁之间;会出现死锁

按操作分:

  • 读锁(共享锁):针对同一份数据,多个读取操作可以同时进行,不互相影响
  • 写锁(排它锁):当前写操作没有完成前,会阻断其他写锁和读锁

行级死锁
在这里插入图片描述

17. 数据库事务四大特性?

原子性(Atomic):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样
一致性(Consistency):在事务开始之前和事务结束以后, 数据库的完整性没有被破坏
隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)
持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

18.ACID、BASE和CAP?

参考:DDBS BASE

参考:DDBS CAP

19.MySQL如何获取当前日期?

SELECT CURRENT_DATE();

20.Mysql驱动程序是什么?

驱动程序主要帮助编程语言与 MySQL 服务端进行通信,如果连接、关闭、传输指令与数据等

21.Innodb引擎有什么特性?

  • 插入缓冲(insert buffer)
  • 二次写(double write)
  • 自适应哈希索引(ahi)
  • 预读(read ahead)

  1. 插入缓冲(insert buffer)解释:

对于聚簇索引,当执行插入操作时,id列会自动增长,页中行记录按id顺序存放不需要随机读取其它页的数据。因此,在这样的情况下,插入操作效率很高。

对于非聚簇索引,可能叶子节点的插入不再有序,这时就需要离散访问非聚集索引页,插入性能变低。

Innodb是怎么解决这个性能变低的情况呢?也就是采用插入缓冲。
对于非聚集类索引的插入和更新操作,不是每一次都直接插入到索引页中,而是先插入到内存中。具体做法是:如果该索引页在缓冲池中,直接插入;否则,先将其放入插入缓冲区中,再以一定的频率和索引页合并,这时,就可以将同一个索引页中的多个插入合并到一个IO操作中,大大提高写性能。

插入缓冲的启用需要满足一下两个条件:
1)索引是非聚簇索引
2)索引不适合唯一的 。
如果辅助索引是唯一的,就不能使用该技术,原因很简单,因为如果这样做,整个索引数据被切分为2部分,无法保证唯一性。


  1. 二次写(double write)的解释:

想象这么一个场景,当数据库正在从内存向磁盘写一个数据页时,数据库宕机,从而导致这个页只写了部分数据,这就是部分写失效,它会导致数据丢失。这时是无法通过redo log恢复的,因为重做日志记录的是对页的物理修改,如果页本身已经损坏,重做日志也无能为力。

从上面分析我们知道,在部分写失效的情况下,我们在应用重做日志之前,需要原始页的一个副本,两次写就是为了解决这个问题。
其原理是这样的:
1)当刷新缓冲池脏页时,并不直接写到数据文件中,而是先拷贝至内存中的两次写缓冲区。
2)接着从两次写缓冲区分两次写入磁盘共享表空间中,每次写入1MB
3)待第2步完成后,再将两次写缓冲区写入数据文件

下面是它的原理图。
在这里插入图片描述
这样就可以解决上文提到的部分写失效的问题,因为在磁盘共享表空间中已有数据页副本拷贝,如果数据库在页写入数据文件的过程中宕机,在实例恢复时,可以从共享表空间中找到该页副本,将其拷贝覆盖原有的数据页,再应用重做日志即可。


  1. 自适应哈希索引(ahi)

哈希索引是一种非常快的等值查找方法(注意:必须是等值,哈希索引对非等值查找方法无能为力),它查找的时间复杂度为常量,InnoDB采用自适用哈希索引技术,它会实时监控表上索引的使用情况,如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引。

之所以该技术称为“自适应”是因为完全由InnoDB自己决定,不需要DBA人为干预。它是通过缓冲池中的B+树构造而来,且不需要对整个表建立哈希索引,因此它的数据非常快。


  1. 预读

参考:https://www.cnblogs.com/geaozhang/p/7397699.html

22.索引对性能有哪些影响?

优点:
减少数据库服务器需要扫描的数据量
帮助数据库服务器避免排序和临时表
将随机 I/O 变顺序I/O
提高查询速度
唯一索引,能保证数据的唯一性

缺点:
索引的创建和维护耗时随着数据量的增加而增加
对表中数据进行增删改时,索引也要动态维护,降低了数据的维护速度
增大磁盘占用

发布了431 篇原创文章 · 获赞 329 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/No_Game_No_Life_/article/details/105411980