互联网科技Java

MySQL数据库经典面试题解析(收藏版)一定要收藏!

2020-09-14  本文已影响0人  小美人鱼失去的腿

前言

100道MySQL数据库经典面试题解析,已经上传github啦

github.com/whx123/Java…

数据库

1. MySQL 索引使用有哪些注意事项呢?

可以从三个维度回答这个问题:索引哪些情况会失效,索引不适合哪些场景,索引规则

索引哪些情况会失效

索引不适合哪些场景

索引的一些潜规则

2. MySQL 遇到过死锁问题吗,你是如何解决的?

我排查死锁的一般步骤是酱紫的:

3. 日常工作中你是怎么优化SQL的?

可以从这几个维度回答这个问题:

4. 说说分库与分表的设计

分库分表方案,分库分表中间件,分库分表可能遇到的问题

分库分表方案:

常用的分库分表中间件:

分库分表可能遇到的问题

5. InnoDB与MyISAM的区别

6. 数据库索引的原理,为什么要用 B+树,为什么不用二叉树?

可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数,为什么不是二叉树,为什么不是平衡二叉树,为什么不是B树,而偏偏是B+树呢?

为什么不是一般二叉树?

如果二叉树特殊化为一个链表,相当于全表扫描。平衡二叉树相比于二叉查找树来说,查找效率更稳定,总体的查找速度也更快。

为什么不是平衡二叉树呢?

我们知道,在内存比在磁盘的数据,查询效率快得多。如果树这种数据结构作为索引,那我们每查找一次数据就需要从磁盘中读取一个节点,也就是我们说的一个磁盘块,但是平衡二叉树可是每个节点只存储一个键值和数据的,如果是B树,可以存储更多的节点数据,树的高度也会降低,因此读取磁盘的次数就降下来啦,查询效率就快啦。

那为什么不是B树而是B+树呢?

1)B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点中不仅存储键值,也会存储数据。innodb中页的默认大小是16KB,如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快。

2)B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的,链表连着的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。

7. 聚集索引与非聚集索引的区别

何时使用聚集索引或非聚集索引?

image

8. limit 1000000 加载很慢的话,你是怎么解决的呢?

方案一:如果id是连续的,可以这样,返回上次查询的最大记录(偏移量),再往下limit

<pre language="javascript" code_block="true">select id,name from employee where id>1000000 limit 10.</pre>

方案二:在业务允许的情况下限制页数:

建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。

方案三:order by + 索引(id为索引)

<pre language="javascript" code_block="true">select id,name from employee order by id limit 1000000,10</pre>

方案四:利用延迟关联或者子查询优化超多分页场景。(先快速定位需要获取的id段,然后再关联)

<pre language="javascript" code_block="true">SELECT a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b where a.id=b.id</pre>

9. 如何选择合适的分布式主键方案呢?

10. 事务的隔离级别有哪些?MySQL的默认隔离级别是什么?

Mysql默认的事务隔离级别是可重复读(Repeatable Read)

11. 什么是幻读,脏读,不可重复读呢?

12. 在高并发情况下,如何做到安全的修改同一行数据?

要安全的修改同一行数据,就要保证一个线程在修改时其它线程无法更新这行记录。一般有悲观锁和乐观锁两种方案~

使用悲观锁

悲观锁思想就是,当前线程要进来修改数据时,别的线程都得拒之门外~ 比如,可以使用select…for update ~

<pre language="javascript" code_block="true">select * from User where name=‘jay’ for update</pre>

以上这条sql语句会锁定了User表中所有符合检索条件(name=‘jay’)的记录。本次事务提交之前,别的线程都无法修改这些记录。

使用乐观锁

乐观锁思想就是,有线程过来,先放过去修改,如果看到别的线程没修改过,就可以修改成功,如果别的线程修改过,就修改失败或者重试。实现方式:乐观锁一般会使用版本号机制或CAS算法实现。

13. 数据库的乐观锁和悲观锁。

悲观锁:

悲观锁她专一且缺乏安全感了,她的心只属于当前事务,每时每刻都担心着它心爱的数据可能被别的事务修改,所以一个事务拥有(获得)悲观锁后,其他任何事务都不能对数据进行修改啦,只能等待锁被释放才可以执行。

image

乐观<typo id="typo-4031" data-origin="锁" ignoretag="true">锁</typo>:

乐观锁的“乐观情绪”体现在,它认为数据的变动不会太频繁。因此,它允许多个事务同时对数据进行变动。实现方式:乐观锁一般会使用版本号机制或CAS算法实现。

image

14. SQL优化的一般步骤是什么,怎么看执行计划(explain),如何理解其中各个字段的含义。

15. select for update有什么含义,会锁表还是锁行还是其他。

select for update 含义

select查询语句是不会加锁的,但是select for update除了有查询的作用外,还会加锁呢,而且它是悲观锁哦。至于加了是行锁还是表锁,这就要看是不是用了索引/主键啦。

没用索引/主键的话就是表锁,否则就是是行锁。

select for update 加锁验证

表结构:

<pre language="javascript" code_block="true">//id 为主键,name为唯一索引
CREATE TABLE account (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
balance int(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_name (name) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8</pre>

id为主键,select for update 1270070这条记录时,再开一个事务对该记录更新,发现更新阻塞啦,其实是加锁了。如下图:

image

我们再开一个事务对另外一条记录1270071更新,发现更新成功,因此,如果查询条件用了索引/主键,会加行锁~

image

我们继续一路向北吧,换普通字段balance吧,发现又阻塞了。因此,没用索引/主键的话,select for update加的就是表锁

image

16. MySQL事务得四大特性以及实现原理

image

事务ACID特性的实现思想

17. 如果某个表有近千万数据,CRUD比较慢,如何优化。

分库分表

某个表有近千万数据,可以考虑优化表结构,分表(水平分表,垂直分表),当然,你这样回答,需要准备好面试官问你的分库分表相关问题呀,如

索引优化

除了分库分表,优化表结构,当然还有所以索引优化等方案~

18. 如何写sql能够有效的使用到复合索引。

复合索引,也叫组合索引,用户可以在多个列上建立索引,这种索引叫做复合索引。

当我们创建一个组合索引的时候,如(k1,k2,k3),相当于创建了(k1)、(k1,k2)和(k1,k2,k3)三个索引,这就是最左匹配原则。

<pre language="javascript" code_block="true">select * from table where k1=A AND k2=B AND k3=D </pre>

有关于复合索引,我们需要关注查询Sql条件的顺序,确保最左匹配原则有效,同时可以删除不必要的冗余索引。

19. mysql中in 和exists的区别。

这个,跟一下demo来看更刺激吧,啊哈哈

假设表A表示某企业的员工表,表B表示部门表,查询所有部门的所有员工,很容易有以下SQL:

<pre language="javascript" code_block="true">select * from A where deptId in (select deptId from B);</pre>

这样写等价于:

先查询部门表B

select deptId from B

再由部门deptId,查询A的员工

select * from A where A.deptId = B.deptId

可以抽象成这样的一个循环:

<pre language="javascript" code_block="true"> List<> resultSet ;
for(int i=0;i<B.length;i++) {
for(int j=0;j<A.length;j++) {
if(A[i].id==B[j].id) {
resultSet.add(A[i]);
break;
}
}
}</pre>

显然,除了使用in,我们也可以用exists实现一样的查询功能,如下:

<pre language="javascript" code_block="true">select * from A where exists (select 1 from B where A.deptId = B.deptId); </pre>

因为exists查询的理解就是,先执行主查询,获得数据后,再放到子查询中做条件验证,根据验证结果(true或者false),来决定主查询的数据结果是否得意保留。

那么,这样写就等价于:

select * from A,先从A表做循环

select * from B where A.deptId = B.deptId,再从B表做循环.

同理,可以抽象成这样一个循环:

<pre language="javascript" code_block="true"> List<> resultSet ;
for(int i=0;i<A.length;i++) {
for(int j=0;j<B.length;j++) {
if(A[i].deptId==B[j].deptId) {
resultSet.add(A[i]);
break;
}
}
}</pre>

数据库最费劲的就是跟程序链接释放。假设链接了两次,每次做上百万次的数据集查询,查完就走,这样就只做了两次;相反建立了上百万次链接,申请链接释放反复重复,这样系统就受不了了。即mysql优化原则,就是小表驱动大表,小的数据集驱动大的数据集,从而让性能更优。

因此,我们要选择最外层循环小的,也就是,如果B的数据量小于A,适合使用in,如果B的数据量大于A,即适合选择exists,这就是in和exists的区别。

20. 数据库自增主键可能遇到什么问题。

21. MVCC熟悉吗,它的底层原理?

MVCC,多版本并发控制,它是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。

MVCC需要关注这几个知识点:

22. 数据库中间件了解过吗,sharding jdbc,mycat?

23. MYSQL的主从延迟,你怎么解决?

嘻嘻,先复习一下主从复制原理吧,如图:

image

主从复制分了五个步骤进行:

主从同步延迟的原因

一个服务器开放N个链接给客户端来连接的,这样有会有大并发的更新操作, 但是从服务器的里面读取binlog的线程仅有一个,当某个SQL在从服务器上执行的时间稍长 或者由于某个SQL要进行锁表就会导致,主服务器的SQL大量积压,未被同步到从服务器里。这就导致了主从不一致, 也就是主从延迟。

主从同步延迟的解决办法

24. 说一下大表查询的优化方案

25. 什么是数据库连接池?为什么需要数据库连接池呢?

连接池基本原理: 数据库连接池原理:在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。

应用程序和数据库建立连接的过程:

数据库连接池好处:

26. 一条SQL语句在MySQL中如何执行的?

先看一下Mysql的逻辑架构图吧~

image

查询语句:

27. InnoDB引擎中的索引策略,了解过吗?

索引下推优化是 MySQL 5.6 引入的, 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

28. 数据库存储日期格式时,如何考虑时区转换问题?

如何考虑时区转换问题/看一下这个吧: 数据库存储日期格式时,如何考虑时区转换问题?

29. 一条sql执行过长的时间,你如何优化,从哪些方面入手?

30. MYSQL数据库服务器性能分析的方法命令有哪些?

Bytes_received和Bytes_sent 和服务器之间来往的流量。

Com_*服务器正在执行的命令。

Created_*在查询执行期限间创建的临时表和文件。

Handler_*存储引擎操作。

Select_*不同类型的联接执行计划。

Sort_*几种排序信息。

31. Blob和text有什么区别?

32. mysql里记录货币用什么字段类型比较好?

33. Mysql中有哪几种锁,列举一下?

image

如果按锁粒度划分,有以下3种:

34. Hash索引和B+树区别是什么?你在设计索引是怎么抉择的?

35. mysql 的内连接、左连接、右连接有什么区别?

36. 说说MySQL 的基础架构图

image

Mysql逻辑架构图主要分三层:

37. 什么是内连接、外连接、交叉连接、笛卡尔积呢?

38. 说一下数据库的三大范式

39. mysql有关权限的表有哪几个呢?

MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些权限表分别user,db,table_priv,columns_priv和host。

40. Mysql的binlog有几种录入格式?分别有什么区别?

有三种格式哈,statement,row和mixed。

statement,每一条会修改数据的sql都会记录在binlog中。不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制。

row,不记录sql语句上下文相关信息,仅保存哪条记录被修改。记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大。

mixed,一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row。

41. InnoDB引擎的4大特性,了解过吗

42. 索引有哪些优缺点?

优点:

缺点:

43. 索引有哪几种类型?

44. 创建索引有什么原则呢?

45. 创建索引的三种方式

<pre language="javascript" code_block="true">CREATE TABLE employee (
id int(11) NOT NULL,
name varchar(255) DEFAULT NULL,
age int(11) DEFAULT NULL,
date datetime DEFAULT NULL,
sex int(1) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_name (name) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;</pre>

<pre language="javascript" code_block="true">ALTER TABLE table_name ADD INDEX index_name (column);
复制代</pre>

<pre language="javascript" code_block="true">CREATE INDEX index_name ON table_name (column);</pre>

46. 百万级别或以上的数据,你是如何删除的?

47. 什么是最左前缀原则?什么是最左匹配原则?

最左前缀原则,就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。当我们创建一个组合索引的时候,如(k1,k2,k3),相当于创建了(k1)、(k1,k2)和(k1,k2,k3)三个索引,这就是最左匹配原则。。

48. B树和B+树的区别,数据库为什么使用B+树而不是B树?

B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的,链表连着的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。.B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点中不仅存储键值,也会存储数据。innodb中页的默认大小是16KB,如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快.

49. 覆盖索引、回表等这些,了解过吗?

网上这篇文章讲得很清晰: mysql覆盖索引与回表

50. B+树在满足聚簇索引和覆盖索引的时候不需要回表查询数据?

在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据,这就是聚簇索引和非聚簇索引。 在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引。如果没有唯一键,则隐式的生成一个键来建立聚簇索引。当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询。

51. 何时使用聚簇索引与非聚簇索引

image

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

不一定,如果查询语句的字段全部命中了索引,那么就不必再进行回表查询(哈哈,覆盖索引就是这么回事)。

举个简单的例子,假设我们在学生表的上建立了索引,那么当进行select age from student where age < 20的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询。

53. 组合索引是什么?为什么需要注意组合索引中的顺序?

组合索引,用户可以在多个列上建立索引,这种索引叫做组合索引。

因为InnoDB引擎中的索引策略的最左原则,所以需要注意组合索引中的顺序。

54. 什么是数据库事务?

数据库事务(简称:事务),是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。

55. 隔离级别与锁的关系

回答这个问题,可以先阐述四种隔离级别,再阐述它们的实现原理。隔离级别就是依赖锁和MVCC实现的。

可以看我这篇文章哈:一文彻底读懂MySQL事务的四大隔离级别

56. 按照锁的粒度分,数据库锁有哪些呢?锁机制与InnoDB锁算法

image

57. 从锁的类别角度讲,MySQL都有哪些锁呢?

从锁的类别上来讲,有共享锁和排他锁。

<typo id="typo-14585" data-origin="锁" ignoretag="true">锁</typo>兼容性如下:

image

58. MySQL中InnoDB引擎的行锁是怎么实现的?

基于索引来完成行锁的。

<pre language="javascript" code_block="true">select * from t where id = 666 for update;</pre>

for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将实行表锁。

59. 什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。看图形象一点,如下:

image

死锁有四个必要条件:互斥条件,请求和保持条件,环路等待条件,不剥夺条件。

解决死锁思路,一般就是切断环路,尽量避免并发形成环路。

如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

如果业务处理不好可以用分布式事务锁或者使用乐观锁

死锁与索引密不可分,解决索引问题,需要合理优化你的索引,

有兴趣的朋友,可以看我的这篇死锁分析: 手把手教你分析Mysql死锁问题

60. 为什么要使用视图?什么是视图?

为什么要使用视图?

为了提高复杂SQL语句的复用性和表操作的安全性,MySQL数据库管理系统提供了视图特性。

什么是视图?

视图是一个虚拟的表,是一个表中的数据经过某种筛选后的显示方式,视图由一个预定义的查询select语句组成。

61. 视图有哪些特点?哪些使用场景?

视图特点:

视图用途: 简化sql查询,提高开发效率,兼容老的表结构。

视图的常见使用场景:

62. 视图的优点,缺点,讲一下?

63. count(1)、count(*) 与 count(列名) 的区别?

64. 什么是游标?

游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。

65. 什么是存储过程?有哪些优缺点?

存储过程,就是一些编译好了的SQL语句,这些SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后给这些代码块取一个名字,在用到这个功能的时候调用即可。

优点:

缺点:

66. 什么是触发器?触发器的使用场景有哪些?

触发器,指一段代码,当触发某个事件时,自动执行这些代码。

使用场景:

67. MySQL中都有哪些触发器?

MySQL 数据库中有六种触发器:

68. 超键、候选键、主键、外键分别是什么?

69. SQL 约束有哪几种呢?

70. 谈谈六种关联查询,使用场景。

71. varchar(50)中50的<typo id="typo-16960" data-origin="涵义" ignoretag="true">涵义</typo>

72. mysql中int(20)和char(20)以及varchar(20)的区别

73. drop、delete与truncate的区别

image

74. UNION与UNION ALL的区别?

75. SQL的生命周期?

服务器与数据库建立连接

数据库进程拿到请求sql

解析并生成执行计划,执行

读取数据到内存,并进行逻辑处理

通过步骤一的连接,发送结果到客户端

关掉连接,释放资源

76. 一条Sql的执行顺序?

image

77. 列值为NULL时,查询是否会用到索引?

列值为NULL也是可以走索引的

计划对列进行索引,应尽量避免把它设置为可空,因为这会让 MySQL 难以优化引用了可空列的查询,同时增加了引擎的复杂度

78. 关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

优化慢查询:

79. 主键使用自增ID还是UUID,为什么?

如果是单机的话,选择自增ID;如果是分布式系统,优先考虑UUID吧,但还是最好自己公司有一套分布式唯一ID生产方案吧。

80. mysql自增主键用完了怎么办?

自增主键一般用int类型,一般达不到最大值,可以考虑提前分库分表的。

81. 字段为什么要求定义为not null?

null值会占用更多的字节,并且null有很多坑的。

82. 如果要存储用户的密码散列,应该使用什么字段进行存储?

密码散列,盐,用户身份证号等固定长度的字符串,应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率。

83. Mysql驱动程序是什么?

这个jar包: mysql-connector-java-5.1.18.jar

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

84. 如何优化长难的查询语句?有实战过吗?

85. 优化特定类型的查询语句

平时积累吧:

86. MySQL数据库cpu飙升的话,要怎么处理呢?

排查过程:

处理:

其他情况:

也有可能是每个 sql 消耗资源并不多,但是突然之间,有大量的 session 连进来导致 cpu 飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等

87. 读写分离常见方案?

88. MySQL的复制原理以及流程

主从复制原理,简言之,就三步曲,如下:

如下图所示:

image

上图主从复制分了五个步骤进行:

步骤一:主库的更新事件(update、insert、delete)被写到binlog

步骤二:从库发起连接,连接到主库。

步骤三:此时主库创建一个binlog dump thread,把binlog的内容发送到从库。

步骤四:从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log

步骤五:还会创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db

89. MySQL中DATETIME和TIMESTAMP的区别

存储精度都为秒

区别:

90. Innodb的事务实现原理?

91. 谈谈MySQL的Explain

Explain 执行计划包含字段信息如下:分别是 id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra 等12个字段。

我们重点关注的是type,它的属性排序如下:

<pre language="javascript" code_block="true">system > const > eq_ref > ref > ref_or_null >
index_merge > unique_subquery > index_subquery >
range > index > ALL</pre>

92. Innodb的事务与日志的实现方式

有多少种日志

innodb两种日志redo和undo。

日志的存放形式

事务是如何通过日志来实现的

93. MySQL中TEXT数据类型的最大长度

94. 500台db,在最快时间之内重启。

95. 你是如何监控你们的数据库的?你们的慢日志都是怎么查询的?

监控的工具有很多,例如zabbix,lepus,我这里用的是lepus

96. 你是否做过主从一致性校验,如果有,怎么做的,如果没有,你打算怎么做?

主从一致性校验有多种工具 例如checksum、mysqldiff、pt-table-checksum等

97. 你们数据库是否支持emoji表情存储,如果不支持,如何操作?

更换字符集utf8-->utf8mb4

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

SELECT CURRENT_DATE();

99. 一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录。

1、如果A表TID是自增长,并且是连续的,B表的ID为索引 select * from a,b where a.tid = b.id and a.tid>500000 limit 200;

2、如果A表的TID不是连续的,那么就需要使用覆盖索引.TID要么是主键,要么是辅助索引,B表ID也需要有索引。 select * from b , (select tid from a limit 50000,200) a where b.id = a .tid;

100. Mysql一条SQL加锁分析

一条SQL加锁,可以分9种情况进行:

如果答案整理有错,欢迎指出哈,感激不尽~

上一篇 下一篇

猜你喜欢

热点阅读