JAVA开发面试_Mysql篇

目录

 

事务4大特性?这4个特性mysql如何保证实现的?

事务隔离级别,4个隔离级别分别有什么并发问题?

Mysql默认隔离级别?如何保证并发安全?

RR和RC如何实现的?RR使用场景?

隔离级别的单位是数据表还是数据行?如串行化级别,两个事务访问不同的数据行,能并发?

存储引擎Innodb和Myisam的区别以及使用场景

 介绍Inodb锁机制,行锁,表锁,意向锁

介绍MVCC

哈希索引是如何实现的?

数据库索引为什么使用B+树,相对于B树有什么优点?为什么不能红黑树?

聚簇索引和非聚簇索引区别

回表查询和覆盖索引

如何创建索引?

如何避免全表扫描?

Explain语句各字段的意义

最左前缀!!联合索引B+树是如何建立的?是如何查询的?当where子句中出现>时,联合索引命中是如何的? 

MySQL中一条SQL语句的执行过程

数据库几大范式

left join,right join,inner join,outer join的含义及区别

mysql主从复制过程,binlog记录格式,异步复制、同步复制、半同步复制模式区别

主从复制或读写分离等数据不一致性问题以及如何解决


事务4大特性?这4个特性mysql如何保证实现的?

事务4大特性:原子性、一致性、隔离性、持久性

​ 原⼦性: 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么全不执行

​ 一致性: 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;

​ 隔离性: 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;

​ 持久性: ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。

实现保证(bin log和reply log)

​ MySQL的存储引擎InnoDB使用重做日志保证一致性与持久性回滚日志保证原子性,使用各种来保证隔离性

事务隔离级别,4个隔离级别分别有什么并发问题?

隔离级别 并发问题

读未提交

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

读已提交RC

R允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣。

可重复读RR

同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。

可串行化

最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级别可以防⽌脏读、不可重复读以及幻读。

Mysql默认隔离级别?如何保证并发安全?

同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改;

 可重复读是有可能出现幻读的,如果要保证绝对的安全只能把隔离级别设置成SERIALIZABLE;这样所有事务都只能顺序执行,自然不会因为并发有什么影响了,但是性能会下降许多。

第二种方式,使用更新的版本控制。维护一个字段作为updateversion,修改时updateversion也作为一个参数传入,在条件语句中添加例如where id=? and update_version = ? 当然set里面要update_version+1。这样可以控制到每次只能有一个人更新一个版本。

RR和RC如何实现的?RR使用场景?

事务隔离级别RC(read commit)和RR(repeatable read)两种事务隔离级别基于多版本并发控制MVCC(multi-version concurrency control)来实现。

 由于RC隔离级别需要保持语句级别的一致性,事务中每一次读取都是访问当前时间点的已提交数据,因此事务中多条查询语句会创建多个不同的ReadView,开销较大,复杂度更高;而对于RR隔离级别,仅需要一个版本的ReadView,消耗更少,因此Mysql默认使用RR隔离级别。

RC隔离级别获得的是语句级读一致性;RR隔离级别获得的是事务级读一致性

 对于RC隔离级别,访问的数据是每次语句执行时间点的数据,而对于RR隔离级别,访问的数据是事务中第一条语句执行时间点的数据。

隔离级别的单位是数据表还是数据行?如串行化级别,两个事务访问不同的数据行,能并发?

  • ​ 读未提交:不加锁
  • ​ 读已提交:加行锁,只锁要修改的行
  • ​ 可重复读:加行锁,锁定的是查询的行
  • ​ 可串行化:加表锁,在读取的每张表上加锁
  • ​ 串行化级别:读不同的行,可以并发
  •  
  • 存储引擎Innodb和Myisam的区别以及使用场景

 

Myisam:支持表锁,适合读密集的场景,不支持外键,不支持事务,索引与数据在不同的文件

Innodb:支持行、表锁,默认为行锁,适合并发场景,支持外键,支持事务,索引与数据同一文件

 介绍Inodb锁机制,行锁,表锁,意向锁

InnoDB⽀持⾏级锁(row-level locking)和表级锁,默认为⾏级锁

InnoDB按照不同的分类的锁:

(1)共享/排它锁(Shared and Exclusive Locks):行级别锁,

(2)意向锁(Intention Locks),表级别锁

(3)间隙锁(Gap Locks),锁定一个区间

(4)记录锁(Record Locks),锁定一个行记录

表级锁​

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

行级锁

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

  • 记录锁(Record Lock): 对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项;
  • 间隙锁(Gap Lock): 对索引项之间的“间隙”加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁),不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行。
  • Next-key Lock: 锁定索引项本身和索引范围。即Record Lock和Gap Lock的结合。可解决幻读问题。
  • 意向锁

    ​ 当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。

  • 介绍MVCC

  • MVCC是一种多版本并发控制机制,在大多数情况下代替行级锁,使用MVCC,能降低其系统开销.

​ MVCC是通过保存数据在某个时间点的快照来实现的. 不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制.

​ InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列,分别保存了这个行的创建时间,一个保存的是行的删除时间。这里存储的并不是实际的时间值,而是系统版本号(可以理解为事务的ID),每开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID.

​ InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.

​ 1.MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read).

​ 2.Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.

​ 原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。客观上,我们认为他就是乐观锁的一整实现方式,就是每行都有版本号,保存时根据版本号决定是否成功。

哈希索引是如何实现的?

哈希索引用索引列的值计算该值的hashCode,然后在hashCode相应的位置存该执行位置值所在行数据的 物理位置,因为使用散列算法,因此访问速度非常快,但是一个值只能对应一个hashCode,而且是散列的分布方式,因此哈希索引不支持范围查找和排序的功能

数据库索引为什么使用B+树,相对于B树有什么优点?为什么不能红黑树?

因为:

​ B+树的磁盘读写代价低,更少的查询次数,查询效率更加稳定,有利于对数据库的扫描

​ 相对B树,B+树是B树的升级版,只是把非叶子节点冗余一下,这么做的好处是为了提高范围查找的效率,解决数据库遍历效率低下问题;B+树只有叶节点存放数据,其余节点用来索引,而B树是每个索引节点都会有Data域。

​ 在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况。所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B树与B+树可以有多个子女,从几十到上千,可以降低树的高度。

磁盘预读原理:将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O

聚簇索引和非聚簇索引区别

​ 聚簇索引:将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据

​ 非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置

​ 聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。

回表查询和覆盖索引

普通索引 需要扫描两遍索引树

(1)先通过普通索引定位到主键值id=5;

(2)在通过聚集索引定位到行记录;

这就是所谓的回表查询先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。

覆盖索引:如果where条件的列和返回的数据在一个索引中,那么不需要回查表,那么就叫覆盖索引。

实现覆盖索引:常见的方法是,将被查询的字段,建立到联合索引里去。

如何创建索引?

CREATE TABLE 表名(
    字段名 数据类型 [完整性约束条件],
       ……,
    [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY
    [索引名](字段名1 [(长度)] [ASC | DESC]) [USING 索引方法]
);

UNIQUE:可选。表示索引为唯一性索引

FULLTEXT:可选。表示索引为全文索引。

SPATIAL:可选。表示索引为空间索引

INDEX和KEY:用于指定字段为索引,两者选择其中之一就可以了,作用是一样的。

索引名:可选。给创建的索引取一个新名称。

字段名1:指定索引对应的字段的名称,该字段必须是前面定义好的字段。

长度:可选。指索引的长度,必须是字符串类型才可以使用。

ASC:可选。表示升序排列。

DESC:可选。表示降序排列。

注:索引方法默认使用B+TREE。

ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL]  INDEX | KEY  [索引名] (字段名1 [(长度)] [ASC | DESC]) [USING 索引方法]; 
或 
CREATE  [UNIQUE | FULLTEXT | SPATIAL]  INDEX  索引名 ON  表名(字段名) [USING 索引方法];

如何避免全表扫描?

1.对查询进行优化,应考虑在 where 及 order by 涉及的列上建立索引。

2.应尽量避免在 where 子句中对字段进行 null 值判断

3.应尽量避免在 where 子句中使用!=或<>操作符

4.in 和 not in 要慎用

否则将导致引擎放弃使用索引而进行全表扫描

Explain语句各字段的意义

mysql> explain select * from staff;

+----+-------------+-------+------+---------------+------+---------+------+------+-------+

| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |

+----+-------------+-------+------+---------------+------+---------+------+------+-------+

|  1 | SIMPLE      | staff | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |

+----+-------------+-------+------+---------------+------+---------+------+------+-------+

1 row in set

列 含义

id 查询序号,序号越大越先执行,一样则按顺序执行

select_type 查询类型,SIMPLE、PRIMARY、UNION、SUBQUERY等

table 表名

type join类型,const,eq_ref,ref等

possible_keys join类型

key 实际选择的索引

ken_len 索引的长度

ref 与索引作比较的列

rows 要检索的行数

Extra 额外信息

最左前缀!!联合索引B+树是如何建立的?是如何查询的?当where子句中出现>时,联合索引命中是如何的? 

​ 最左前缀原则主要使用在联合索引中,联合索引的B+Tree是按照第一个关键字进行索引排列的。

​ 联合索引的底层是一颗B+树,那么联合索引的底层也就是一颗B+树,只不过联合索引的B+树节点中存储的是键值。由于构建一棵B+树只能根据一个值来确定索引关系,所以数据库依赖联合索引最左的字段来构建。

​ 采用>、<等进行匹配都会导致后面的列无法走索引,因为通过以上方式匹配到的数据是不可知的。

MySQL中一条SQL语句的执行过程

查询语句

select * from student  A where A.age='18' and A.name='张三';

结合上面的说明,我们分析下这个语句的执行流程:

先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在mysql8.0版本以前,会先查询缓存,以这条sql语句为key在内存中查询是否有结果,如果有直接缓存,如果没有,执行下一步。

通过分析器进行词法分析,提取sql语句的关键元素,比如提取上面这个语句是查询select,提取需要查询的表名为tb_student,需要查询所有的列,查询条件是这个表的id='1'。然后判断这个sql语句是否有语法错误,比如关键词是否正确等等,如果检查没问题就执行下一步。

接下来就是优化器进行确定执行方案,上面的sql语句,可以有两种执行方案: a.先查询学生表中姓名为“张三”的学生,然后判断是否年龄是18。 b.先找出学生中年龄18岁的学生,然后再查询姓名为“张三”的学生。 那么优化器根据自己的优化算法进行选择执行效率最好的一个方案(优化器认为,有时候不一定最好)。那么确认了执行计划后就准备开始执行了。

进行权限校验,如果没有权限就会返回错误信息,如果有权限就会调用数据库引擎接口,返回引擎的执行结果。

更新语句

update student A set A.age='19' where A.name='张三';

我们来给张三修改下年龄,在实际数据库肯定不会设置年龄这个字段的,不然要被技术负责人打的。其实这条语句也基本上会沿着上一个查询的流程走,只不过执行更新的时候肯定要记录日志啦,这就会引入日志模块了,mysql 自带的日志模块式binlog(归档日志),所有的存储引擎都可以使用,我们常用的InnoDB引擎还自带了一个日志模块redo log,我们就以InnoDB模式下来探讨这个语句的执行流程。流程如下:

先查询到张三这一条数据,如果有缓存,也是会用到缓存。

然后拿到查询的语句,把 age 改为19,然后调用引擎API接口,写入这一行数据,InnoDB引擎把数据保存在内存中,同时记录redo log,此时redo log进入prepare状态,然后告诉执行器,执行完成了,随时可以提交。

执行器收到通知后记录binlog,然后调用引擎接口,提交redo log 为提交状态。

更新完成。

数据库几大范式

第一范式(1NF)列不可分割

第二范式(2NF)属性完全依赖于主键 [ 消除部分子函数依赖 ]

第三范式(3NF)属性不依赖于其它非主属性 [ 消除传递依赖 ]

left join,right join,inner join,outer join的含义及区别

left join(左联接) 返回包括左表中的所有记录和右表中关联字段相等的记录

right join(右联接) 返回包括右表中的所有记录和左表中关联字段相等的记录

inner join(等值连接) 只返回两个表中关联字段相等的行

mysql主从复制过程,binlog记录格式,异步复制、同步复制、半同步复制模式区别

MySQl主从复制

原理:将主服务器的binlog日志复制到从服务器上执行一遍,达到主从数据的一致状态。

过程:从库开启一个I/O线程,向主库请求Binlog日志。主节点开启一个binlog dump线程,检查自己的二进制日志,并发送给从节点;从库将接收到的数据保存到中继日志(Relay log)中,另外开启一个SQL线程,把Relay中的操作在自身机器上执行一遍

优点

作为备用数据库,并且不影响业务

可做读写分离,一般是一个库,一个或多个读库,分布在不同的服务器上,充分发挥服务器和数据库的性能,但要保证数据的一致性

异步复制:

​ 在异步复制中,主库执行完操作后,写入binlog日志后,就返回客户端,这一动作就结束了,并不会验证从库有没有收到,完不完整,所以这样可能会造成数据的不一致

半同步复制:

​ 当主库每提交一个事务后,不会立即返回,而是等待其中一个从库接收到Binlog并成功写入Relay-log中才返回客户端,所以这样就保证了一个事务至少有两份日志,一份保存在主库的Binlog,另一份保存在其中一个从库的Relay-log中,从而保证了数据的安全性和一致性。

全同步复制:

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

主从复制或读写分离等数据不一致性问题以及如何解决

"主从复制有延时",这个延时期间读取从库,可能读到不一致的数据。

半同步复制法

​ 当主库每提交一个事务后,不会立即返回,而是等待其中一个从库接收到Binlog并成功写入Relay-log中才返回客户端,所以这样就保证了一个事务至少有两份日志,一份保存在主库的Binlog,另一份保存在其中一个从库的Relay-log中,从而保证了数据的安全性和一致性。

全同步复制法

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

缓存记录写key法

​ 在cache里记录哪些记录发生过的写请求,来路由读主库还是读从库

 

 

猜你喜欢

转载自blog.csdn.net/weixin_37841366/article/details/109128480
今日推荐