mysql面试题

数据库基础

Q:数据库三范式是什么?
第一范式:列不可再分
第二范式:行可以唯一区分,主键约束
第三范式:表的非主属性不能依赖于其他表的非主属性 外键约束
且三大范式是一级一级依赖的,第二范式建立在第一范式上,第三范式建立第一第二范式上。

Q:数据库引擎有哪些?他们有什么区别?(高频)
区别:

  1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
  2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
  3. InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
  4. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
  5. Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;

Q:int(5)跟int(4)有什么区别?
int(M),其中的M表示长度。

int类型占用4个字节,1个字节 8 bit(比特)。存储空间为 2^(4*8),也就是2的32次幂,因此取值范围是-2147483648~2147483647,也就是最大长度是10

其实当我们在选择使用int的类型的时候,不论是int(3)还是int(11),它在数据库里面存储的都是4个字节的长度,在使用int(3)的时候如果你输入的是10,会默认给你存储位010,也就是说这个3代表的是默认的一个长度,当你不足3位时,会帮你补全,当你超过3位时,就没有任何的影响。

对于存储和计算来说,int(10)和int(11)没有区别,10代表数字长度,也就是最大长度是10,如果写成int(11), 插入11位数的时候是插入不进去的,mysql会默认int最大10位(2147483647),2147483648也将插入不了。所以int(1)和int(20)是没有区别的,但是写int(20)会认为对mysql字段类型理解不到位。

另外,TINYINT和INT区别就大了,TINYINT占用1个字节,也就是取值是-128~127。所以尽可能取占用空间小的整数类型。

合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。

Q:mysql中char与varchar的区别?
CHAR的长度是固定的,而VARCHAR2的长度是可以变化的,比如,存储字符串“abc”,对于CHAR(10),表示你存储的字符将占10个字节(包括7个空字符),而同样的VARCHAR2(10)则只占用3个字节的长度,10只是最大值,当你存储的字符小于10时,按实际长度储存。

主键

Q:官方为什么建议采用自增id作为主键?
答案:自增id是连续的,插入过程也是顺序的,总是插入在最后,减少了页分裂,有效减少数据的移动。所以尽量不要使用字符串(如:UUID)作为主键。
自定义的字符串(UUID)主键,后一个数据页中的所有行并不一定比前一个数据页中的行的id大,就会触发页分裂的逻辑。
页分裂的目的就是保证:后一个数据页中的所有行主键id比前一个数据页中主键id大。
另外,在InnoDB存储引擎中,数据页是InnoDB磁盘管理的最小的数据单位,数据页的默认大小为16KB。

事务

Q:数据库事务是什么?
多条sql语句,要么全部成功,要么全部失败。

Q:数据库事务有哪些特性?(高频)
数据库事务特性:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durabiliy)。简称ACID。
原子性:组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有操作都成功,整个事务才会提交。任何一个操作失败,已经执行的任何操作都必须撤销,让数据库返回初始状态。
一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的。即数据不会被破坏。如A转账100元给B,不管操作是否成功,A和B的账户总额是不变的。
隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对彼此产生干扰
持久性:一旦事务提交成功,事务中的所有操作都必须持久化到数据库中。

Q:数据库的隔离级别有哪些?(高频)
读未提交(read-uncommitted)读提交(read-committed) 可重复读(repeatable-read)串行化(serializable)。

Q:mysql默认的数据库隔离级别是什么?(高频)
可重复读(repeatable-read)

Q:为什么mysql要将隔离级别设置为可重复读?为什么mysql不像oracle一样,像事务隔离级别设置为读提交?
读提交的隔离级别,会出现不可重复读。
在读提交的隔离级别下,比如当事务A查询帐户余额为100,事务B将余额取出50并提交,那么事务A再次查询账户时余额为50,这个就是不可重复读。

那既然如此,为什么oracle要把事务隔离级别设置为读提交呢?
mysql为什么要将隔离级别设置为可重复读,更深层的原因见:https://blog.csdn.net/m0_37774696/article/details/88951846

Q:不同的数据库隔离级别会导致哪些问题?(高频)
数据库中的数据可能同时被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性。
1.脏读:A事务读取B事务尚未提交的更改数据,并在这个数据的基础上进行操作。如果恰巧B事务回滚,那么A事务读取到的数据是根本不被承认的。
读未提交的隔离级别,会出现脏读。
2.不可重复读:A事务读取了B事务已经提交的更改数据。(注意,是更改)
读提交的隔离级别,会出现不可重复读。
3.幻读:A事务读取了B事务已经提交的新增数据。(注意,是新增)
可重复读的隔离级别,会出现幻读。
概念讲解:https://www.cnblogs.com/expiator/p/9626123.html
操作示例:https://juejin.im/post/5d8b2a9c518825091471fe2c

Q:可重复读无法解决幻读。只能避免一部分幻读问题。如何避免一部分幻读问题?(高频)

  • 可重复读隔离级是由 MVCC(多版本并发控制)实现的,实现的方式是开始事务后(执行 begin 语句后),在执行第一个查询语句后,会创建一个 Read View,后续的查询语句利用这个 Read View,通过这个 Read View 就可以在 undo log 版本链找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的,即使中途有其他事务插入了新纪录,是查询不出来这条数据的,所以就很好了避免幻读问题。
  • 针对当前读(select ... for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select ... for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。

这两个解决方案是很大程度上解决了 幻读 现象,但是还是有个别的情况造成的幻读现象是无法解决的。

参考资料: https://blog.csdn.net/dw147258dw/article/details/130542074

Mvcc

Q:mysql的可重复读,是怎么实现的?(高频)
使用的的一种叫MVCC的控制方式 ,即Mutil-Version Concurrency Control,多版本并发控制。
具体做法是:
当一个事务开启时会生成一个事务 id。mysql 会将事务的操作记录到 undo log 日志中。在这个记录中每个操作行都会有一个事务 id 和回滚指针。
当你需要查询一个数据时,会先访问日志从最新的记录开始利用回滚指针向上访问。
第一次查询开启时会生成一个 readView(未提交的事务 id 组成的数组+生成的事务最大 id)。如果在日志中当前记录行的事务 id 不超过最大生成的事务 id,也不在未提交事务 id 数组中,则说明是可读的。
这个 readView 是第一次查询时候生成的,以后的查询会复用之前的 readView。如果隔离性是读已提交,则每次查询都会生成一个新的 readView。

简单点说,就是mysql的可重复读是一种快照读,第一次查询时生成一个readView,第二次查询时直接读这个readView。
详情见: https://blog.csdn.net/weixin_43698257/article/details/106582241

Q:MVCC的实现方式是怎样的?(高频)
mvcc的实现原理主要依赖于记录中的三个隐藏字段,undolog,read view来实现的。
在innodb引擎下的表,每个数据行都有隐藏的两列,一列是trx_id,也就是更新(insert、update、delete)这条记录的事务ID;
一列是roll_pointer,回滚指针,指向undo log上个版本;
如果不存在主键的话,还会有第三列row_id,在没有主键的情况下默认生成的主键;

Q:Mysql哪些是当前读,哪些是读快照?
快照读,mvcc加 undo log。快照读,读的是历史版本的数据~
当前读,in share mode(共享锁),insert update delete(排他锁)。

sql

Q:union和union all的区别是什么?
union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
union all:对两个结果集进行并集操作,包括重复行,不进行排序;

Q:讲一下各种join的区别。
JOIN: 如果表中有至少一个匹配,则返回行
INNER JOIN 与 JOIN 是相同的。
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
FULL JOIN: 只要其中一个表中存在匹配,就返回行

Q:讲一下explain。(高频)
它可以对 SELECT 语句进行分析,并输出 SELECT 执行的详细信息,方便针对性地优化。
查询结果的字段如下:

  • select_type: SELECT 查询的类型。包括SIMPLE、PRIMARY、UNION、UNION RESULT等
  • table: 查询的是哪个表
  • partitions: 匹配的分区
  • type(重要): 类型。type值为all,表示全表扫描。type值为const,说明使用了主键索引。
system: 表中只有一条数据. 这个类型是特殊的 const 类型.

const: 针对主键或唯一索引的等值查询扫描, 最多只返回一行数据. const 查询速度非常快, 因为它仅仅读取一次即可.

eq_ref: 此类型通常出现在多表的 join 查询, 表示对于前表的每一个结果, 都只能匹配到后表的一行结果. 并且查询的比较操作通常是 =, 查询效率较高. 

ref: 此类型通常出现在多表的 join 查询, 针对于非唯一或非主键索引, 或者是使用了 最左前缀 规则索引的查询. 

range: 表示使用索引范围查询, 通过索引字段范围获取表中部分数据记录. 这个类型通常出现在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中.
当 type 是 range 时, 那么 EXPLAIN 输出的 ref 字段为 NULL, 并且 key_len 字段是此次查询中使用到的索引的最长的那个.

index: 表示全索引扫描(full index scan), 和 ALL 类型类似, 只不过 ALL 类型是全表扫描, 而 index 类型则仅仅扫描所有的索引, 而不扫描数据.
index 类型通常出现在: 所要查询的数据直接在索引树中就可以获取到, 而不需要扫描数据. 当是这种情况时, extra 字段 会显示 Using index.

all: 表示全表扫描, 这个类型的查询是性能最差的查询之一. 通常来说, 我们的查询不应该出现 ALL 类型的查询, 因为这样的查询在数据量大的情况下, 对数据库的性能是巨大的灾难. 如一个查询是 ALL 类型查询, 那么一般来说可以对相应的字段添加索引来避免.

不同的 type 类型的性能关系如下:
ALL < index < range ~ index_merge < ref < eq_ref < const < system。

  • possible_keys: 此次查询中可能选用的索引
  • key(重要): 此次查询中确切使用到的索引.
  • ref: 哪个字段或常数与 key 一起被使用
  • rows(重要): 显示此查询一共扫描了多少行. 这个是一个估计值.
  • filtered: 表示此查询条件所过滤的数据的百分比
  • extra: 额外信息,比如using index表示使用覆盖索引,using where表示在存储引擎之后进行过滤,using temporary表示使用临时表,using filesort表示对结果进行外部排序。

Q:EXPLAIN的结果,主要看哪些字段?
EXPLAIN结果,重点看key这个字段,key表示此次查询中确切使用到的索引.
其次看 type,有没有走索引。
还可以看下 rows,扫描了多少行,扫描的行越少越好。
如果extra 中,出现了 using filesort,也要注意,尽量避免。

参考资料:https://segmentfault.com/a/1190000008131735

Q:讲一下filesort。
文件排序,也叫 filesort ,通常我们在Mysql中使用explain关键字时,在Extra列中,如果是 Using filesort 就是文件排序。
含义:文件排序的含义是排序的过程将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一 般也是要考虑使用索引来优化的。

index :通过有序索引顺序扫描直接返回有序数据,不需要额外的排序,操作效率较高。
filesort:通过对返回数据进行排序,filesort 并不代表通过磁盘文件排序,而是说明进行了一个排序操作,至于排序操作是否使用了磁盘文件或临时表等,则取决于MySQL服务器对排序参数的设置和需要排序数据的大小。
一般而言,filesort是通过相应的排序算法,将所取得的数据在sort_buffer_size系统变量设置的内存排序区中进行排序,如果内存装载不下,它就会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集。
sort_buffer_size设置的排序区是每个线程独占的,所以同一时刻,MySQL中存在多个sort buffer排序区。
优化:尽量减少额外排序,通过索引直接返回有序的数据。where 条件和order by 使用了相同的索引,并且order by 的顺序和索引顺序相同,并且order by 的字段都是升序或者降序,否则肯定需要额外的排序操作,这样就会出现 filesort。

参考资料:https://blog.csdn.net/qq_41931364/article/details/121869029

sql优化

Q:平常使用过哪些sql优化的手段?(高频)

1、查询语句中不要使用select  *
2、尽量减少子查询,使用关联查询(left join,right join,inner  join)替代
3、减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代
4、or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好)
5、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
6、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0

索引

Q:有哪些数据结构的索引?
B+ Tree索引、哈希索引(Hash Index)、空间数据索引(R-Tree)、全文索引(Full Text)

Q:有哪些类型的索引?
普通索引,唯一索引,主键索引与组合索引
普通索引:仅加速查询
唯一索引:加速查询 + 列值唯一(可以有null)
主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个
组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
全文索引:对文本的内容进行分词,进行搜索

Q:唯一索引和主键有什么区别?
a.主键是一种约束,唯一索引是一种索引;
b.一张表只能有一个主键,但可以创建多个唯一索引;
c.主键创建后一定包含一个唯一索引,唯一索引并不一定是主键;
d.主键不能为null,唯一索引可以为null;
e.主键可以做为外键,唯一索引不行;

Q:索引的数据结构。(高频)
B+树。Mysql支持Hash索引和B+树索引两种。

Q: B+树索引和hash索引的区别。

  • 【hash索引等值查询效率高】如果是等值查询,那么hash索引有明显的优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个键值是唯一的,如果不唯一,则需要先找到下标位置再链式查找。

  • 【hash索引不支持范围查询】从示意图可以知道,hash索引无法支持范围查询,因为原先是有序的键值,但是经过hash算法后,有可能变成不连续的,就没有办法利用索引完成范围查询检索数据。

  • 【hash无法利用索引排序】同样,hash索引也没办法利用索引完成排序,以及like xxx%这样的模糊查询(范围查询)。

  • 【hash索引不支持最左匹配原则】hash索引也不支持多列联合索引的最左前缀匹配规则。

  • 【B+树查询更稳定】B+树索引的关键字检索效率比较平均,在有大量重复键的情况下,hash索引的效率也是极低的,因为存在hash碰撞问题。

Q:B+树和B树的区别有哪些?(高频)
B+ Tree 和 B Tree 不同,B+ Tree 中,只能将数据存储在叶子结点中,内部节点将只包含指针,而 B Tree 可以将数据存储在内部的叶节点中。因此 B+ Tree 的关键优势是中间节点不包含数据,因此 B+ Tree 的大小远小于 B Tree,并且可以将更多数据存储到存储器中。另外,B+ Tree 的每一个叶子节点包含了到相邻的节点的链接,这样可以快速地进行范围遍历。

Q:InnoDB一棵B+树可以存放多少行数据?
几千万。
B+树的深度一般是2~3层,所以假设B+树有三层,且子节点都被填满,每个节点就是一个页,页的大小是16K。而且假设每一行的数据是1K,那么一页就能够存放16行。然后通过一通计算,得出了B+树可以存放的行数是两千万。

Q:使用索引为什么可以加快数据库的检索速度啊?
将无序的数据变成有序(相对)。没有用索引我们是需要遍历双向链表来定位对应的页,现在通过“目录”就可以很快地定位到对应的页上了。
类比翻字典。。查了索引,知道是在第几页,直接去第几页找就行了。不要从头开始翻。

Q:为什么说索引会降低插入、删除、修改等维护任务的速度。
B+树是一颗平衡树,如果我们对这颗树增删改的话,那肯定会破坏它的原有结构。
要维持平衡树,就必须做额外的工作。正因为这些额外的工作开销?导致索引会降低增删改的速度

Q:索引的最左匹配原则指的是什么?
答案:即最左优先,在检索数据时从联合索引的最左边的字段开始匹配,直到遇到范围查询(如:>、<、between、 like等)。

Q:Hash索引和B+树索引有什么区别?主流的使用哪一个比较多?InnoDB存储都支持吗?
Q:组合索引是怎么存储数据的?
组合索引也是一棵B+树,不同的是组合索引的键值不是1个,而是大于等于2个。
Q:组合索引有哪些使用规则?

Q:组合索引的设计要注意什么?

  • 最左匹配原则。
  • 区分度⾼的列放到组合索引前⾯,使业务 SQL 尽可能通过索引定位更少的⾏。

Q:聚簇索引和非聚簇索引有什么区别?
聚簇索引:将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据
非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置

区别:
聚集索引在叶子节点存储的是表中的数据。
非聚集索引在叶子节点存储的是主键和索引列。
使用非聚集索引查询出数据时,拿到叶子上的主键再去查到想要查找的数据。(拿到主键再查找这个过程叫做回表)

Q:聚簇索引和主键有什么关系?
InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引。
(1)如果表定义了主键,则PK就是聚集索引;
(2)如果表没有定义主键,则第一个非空唯一索引(not NULL unique)列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;

Q:什么叫回表?
如果索引的列在 select 所需获得的列中(因为在 mysql 中索引是根据索引列的值进行排序的,所以索引节点中存在该列中的部分值)或者根据一次索引查询就能获得记录就不需要回表,如果 select 所需获得列中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表。

使用聚集索引(主键或第一个唯一索引)就不会回表,普通索引就会回表。

Q:什么叫覆盖索引?
所谓覆盖索引就是指索引中包含了select查询中的所有字段,这种情况下就不需要再进行回表查询了
详情参见: https://blog.csdn.net/liaowenxiong/article/details/120846042

Q:什么叫索引下推?
索引下推(index condition pushdown )简称ICP,

在不使用ICP的情况下,在使用非主键索引(又叫普通索引或者二级索引)进行查询时,存储引擎通过索引检索到数据,然后返回给MySQL服务器,服务器然后判断数据是否符合条件 。

在使用ICP的情况下,如果存在某些被索引的列的判断条件时,MySQL服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合MySQL服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器 。

索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少MySQL服务器从存储引擎接收数据的次数。

参考链接:https://www.jianshu.com/p/d0d3de6832b9

Q:索引的最左前缀原则是什么?
如果不是按照索引的最左列开始查找,则无法使用索引;
不能跳过联合索引中的某些列;
如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找;

Q:索引什么时候不生效?
Q:索引优化策略。

1.最左前缀匹配原则。
2.主键外键一定要建索引
3. 对 where,on,group by,order by 中出现的列使用索引
4.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0
5.对较小的数据列使用索引,这样会使索引文件更小,同时内存中也可以装载更多的索引键
6.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);
7.为较长的字符串使用前缀索引
8.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可
9.不要过多创建索引, 权衡索引个数与DML之间关系,DML也就是插入、删除数据操作。这里需要权衡一个问题,建立索引的目的是为了提高查询效率的,但建立的索引过多,会影响插入、删除数据的速度,因为我们修改的表数据,索引也需要进行调整重建
10.对于like查询,”%”不要放在前面。 
    SELECT * FROM  t_order  WHERE uname LIKE '编程%' -- 走索引 
    SELECT * FROM  t_order  WHERE uname LIKE  '%编程%' -- 不走索引
可以用instr代替左模糊。
instr(title,'name')>0  相当于  title like '%name%' 
instr(title,'name')=1  相当于  title like 'name%' 
instr(title,'name')=0  相当于  title not like '%name%' 
11.查询where条件数据类型不匹配也无法使用索引。字符串与数字比较不使用索引; 

Q:有一个性别字段,男和女,这个字段需要加索引吗?
离散度低的字段,没有必要加索引。

分页查询

Q:mysql分页查询,数据量比较大的时候,有哪些优化?

  • mysql分页查询。用子查询先过滤出id,再分页。
SELECT * FROM tt_product WHERE id > =(select id from tt_product limit 866613, 1) limit 20
  • 如果对于有where 条件,又想走索引用limit的,必须设计一个索引,将其放在where后的第一位,limit用到的主键放第2位,
select id ,title from collect where vtype=1 limit 90000,10;

详情见:https://zhuanlan.zhihu.com/p/375828064

Q:mysql有哪些锁?
加锁机制:乐观锁,悲观锁。
兼容性:共享锁,排他锁。
锁粒度:表锁,行锁,页锁。

Q:讲一下悲观锁、乐观锁。
悲观锁是指总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。具有独占性和排他性。比如,行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁不是数据库层面上的锁,是需要自己手动去加的锁。一般我们添加一个版本字段version来实现。

Q:讲一下共享锁、排它锁。
共享锁:指的就是对于多个不同的事务,对同一个资源共享同一个锁。相当于对于同一把门,它拥有多个钥匙一样。
在执行语句后面加上 lock in share mode 就代表对某些资源加上共享锁了。

排它锁:排它锁,就是指对于多个不同的事务,对同一个资源只能有一把锁。
在需要执行的语句后面加上for update就可以了。

Q:讲一下间隙锁。
间隙锁(Gap Lock):间隙锁是一个在索引记录之间的间隙上的锁,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
间隙锁的出现是为了在innodb的可重复读隔离级别下,解决幻读问题产生的。

Q:行级锁有哪些?
行级锁的种类主要有三类:

  • Record Lock,记录锁,也就是仅仅把一条记录锁上;
  • Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;
  • Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

mysql死锁

Q: mysql如何避免死锁?

  • 事务尽可能小,不要将复杂逻辑放进一个事务里。

  • 涉及多行记录时,约定不同事务以相同顺序访问。

  • 业务中要及时提交或者回滚事务,可减少死锁产生的概率。

  • 表要有合适的索引。

  • 设置事务等待锁的超时时间。当一个事务的等待时间超过该值后,就对这个事务进行回滚,于是锁就释放了,另一个事务就可以继续执行了。在 InnoDB 中,参数 innodb_lock_wait_timeout 是用来设置超时时间的,默认值时 50 秒。

  • 开启主动死锁检测。主动死锁检测在发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑,默认就开启。
    当检测到死锁后,就会出现下面这个提示:

ERROR 1213 (40001):Deadlock found when trying to get lock;try restarting transaction

Q: mysql出现死锁,怎么办?
详情见: https://blog.csdn.net/weixin_44797327/article/details/134611841

binLog、redoLog、undoLog

Q:讲一下binLog、redoLog、undoLog。(高频)

  • binLog(二进制日志, 全称binary log)。用于记录数据库数据变更操作的日志。(除了数据查询语句)。
    binLog 作用:数据备份。数据恢复。数据同步。
    作用:用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。

  • undo log(回滚日志)。作用:保存了事务发生之前的数据的一个版本,可以用于回滚。

使用undolog来实现原子性,如果事务执行过程中出错或者用户执行了rollback,系统通过undolog日志返回事务开始的状态。

  • redo log是InnoDB存储引擎层的日志,又称重做日志文件,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。

使用redolog来实现持久性,只要redolog日志持久化了,当系统崩溃,即可通过redolog把数据恢复。
作用:宕机时可以用 RedoLog 来恢复数据,保证数据的完整性。

Q:binlog有几种格式?
statement:记录的是修改SQL语句。
row:记录的是每行实际数据的变更。
mixed:statement和row模式的混合。

主从架构

Q:为什么要做主从架构?
读写分离,主机写,从机读。提高数据库性能,扛更高的并发。
Q:讲一下主从复制。
主库创建一个binlog dump thread线程,把binlog的内容发送到从库。
从库创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log。
从库还会创建一个SQL线程,从relay log里面读取内容,并将更新内容写入到slave的db(也就是重新在从库里跑一次insert/update语句)。
参考资料:https://blog.csdn.net/darkangel1228/article/details/80003967

Q:讲一下mysql的异步复制,同步复制,半同步复制。
异步复制(Asynchronous replication):
MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。

全同步复制(Fully synchronous replication):
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

半同步复制(Semisynchronous replication):
介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。

参考资料: https://blog.csdn.net/HD243608836/article/details/118221038

Q:什么是主从延迟?
指⼀个写⼊SQL操作在主库执⾏完后,将数据完整同步到从库会有⼀个时间差,称之为主从延迟。还未完整同步到从库,由于读写分离读了从库的旧值,主从不一致,存在主从延迟。

Q:主从延迟排查⽅法?
通过 show slave status 命令输出的 Seconds_Behind_Master 参数的值来判断。
为零:表示主从复制良好
正值:表示主从已经出现延时,数字越⼤,表示从库延迟越严重。

Q:主从复制延迟怎么解决?
如果只是部分业务出现延迟,可以直接用主库去读。这个是比较简单粗暴的方法。

  • 看业务的接受程度。如果不能接受延迟,那么建议强制走主库查询。
  • 可以考虑引入缓存,更新主库后同步写入缓存,保证缓存的及时性提升从库的机器配置,提高从库binlog的同步效率
  • 缩短主、从库的网络距离,减少binlog的网络传输时间
  • 一主多从,每个从库都启一个线程从主库同步binlog,导致主库压力过大,可以采用canal增量订阅&消费 组件,缓解主库压力。
  • 因为数据库必须要等到事务完成之后才会写入binlog,所以减少大事务的执行,尽量控制数量,分批执行。
  • 5.6版本之前,从库是单线程复制,当遇到执行慢的sq时,就会阻塞后面的同步。5.7版本后支持多线程复制,可以在从服务上设置slave parallel workers为一个大于0的数,然后把slave parallel type参 数设置为LOGICAL CLOCK。
  • 为从库增加浮动IP,并通过脚本检测从库的延迟,延迟大于指定阈值时,将浮动IP切换至Master库,追平后再切换回从库。

参考资料: 《我要去大厂系列》

架构

Q:讲一下MySQL基本架构。
MySQL 主要分为 Server 层和引擎层,Server 层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用,redo log 只有 InnoDB 有。
•连接器:身份认证和权限相关(登录 MySQL 的时候)。
•查询缓存:执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
•分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
•优化器: 按照 MySQL 认为最优的方案去执行。
•执行器: 执行语句,然后从存储引擎返回数据。

Q:一条SQL语句在MySQL中如何执行的?
第一步:客户端发送SQL语句到MySQL服务端
第二步:验证连接合法性
第三步:查询缓存
第四步:语法解析和预处理
第五步:查询优化
第六步:调用存储引擎执行
第七步:将结果返回给客户端
详情见: https://www.51cto.com/article/706125.html

Q:一条SQL查询语句是如何执行的?
查询语句的执行流程如下:权限校验 —>(如果命中缓存)查询缓存—>分析器—>优化器—>执行器—>引擎

Q:一条SQL更新语句是如何执行的?
更新语句执行流程如下:分析器—> 执行器 —> 引擎 —> redo log(prepare 状态) —> binlog —> redo log(commit状态)

分库分表 面试题

Q:数据库如何处理海量数据?
分库分表,主从架构,读写分离

Q:什么数据量需要分库分表?
百万级别直接用mysql。
五百万到一千万可以用mysql分区表??(存疑)
千万级别的数据量,可以分库分表。

Q:数据库分库分表,何时分?怎么分?
水平分库/分表,垂直分库/分表
水平分库/表,各个库和表的结构一模一样。
垂直分库/表,各个库和表的结构不一样。

Q:分库分表有哪些中间件?
ShardingJdbc、MyCat

Q:分表策略有哪些?
Hash分表:对某个字段进行hash分表。比如user表可以对user_id值进行hash后拆分成user_1,user_2。。查询后根据id的hash值找到对应的表就可以了。

Q:读写分离怎么做?
主机负责写,从机负责读。

Q:分库分表后,如何跨表/如何跨库查询?
Q:分库分表后,如何跨表/如何跨库join?
待补充。

参考资料:

数据库面试题--开发者必看
数据库要点--索引和锁

posted on 2019-01-08 23:03  乐之者v  阅读(5046)  评论(0编辑  收藏  举报

导航