MySQL面试题,个人总结

目录

MySQL

MySQL同步原理

MySQL为什么要主从同步

redolog(只存在innoDB 物理日志)

有三个重要的指针

binlog(复制\备份+恢复)

innoDB和MyISAM的区别

为什么MyISAM比InnoDB快

数据库的锁

行锁

场景

死锁:

索引的分类

索引的好处和坏处

为什么索引结构默认是b+树索引 *

B树跟B+树

B树

B+树

为什么官方建议使用自增长主键作为索引。 

索引的查询原理

怎么去识别我们写的SQL有没有走索引

Extra sql执行分析

使用索引的注意事项

索引失效

索引下推

MVCC

ReadView机制:

事务

事务带来的问题:

事务的隔离级别:

分布式事务两阶段加锁(提高并发)

规范

sql调优


MySQL

连接器 复制和客户端建立连接、获取权限、维持和管理连接

查询缓存  key是查询的语句 value是查询的结果,有缓存就直接返回给客户端 MySQL8.0开始就没有这个功能了,每次数据改变都需要去更新缓存

分析器

词法分析:SQL类型 每个字符串代表的是什么?

语法分析:判断SQL是否符合mysql的语法规则

优化器:决定走那个索引,或者连表的执行顺序是怎么样的(先查主表还是先查连接表)

CBO:基于成本的优化

RBO:基于规则的优化

执行器:先判断是否有该表权限,执行语句

MySQL同步原理

主服务器将数据的改变记录到二进制的binlog日志中,节点服务器会在一定时间内对主服务器的binlog进行探测是否改变,如果已经改变,用一个线程读取主服务器的binlog内容到节点服务器的relaylog中,再由sql线程负责读取relaylog 更新到节点服务器中,从而保证数据一致。

注意:复制最好保证数据库的版本一致

MySQL为什么要主从同步

1.如果在一个情景下,有一个sql需要锁表,就会导致不能使用读操作,会影响业务,使用主从复制,读写分离,主库锁表的情况下,也可以在从库中读取。

2.主备,当主服务宕机时,由备用服务器来代替主服务器提供服务

redolog(只存在innoDB 物理日志)

数据日志如果每次改动MySQL数据的时候都去直接更新,会导致效率很低,所以使用redolog来保存没有持久化的数据,规定时间mysql在进行读取数据进行持久化,同时服务器宕机也能够保证数据不会丢失。

支持4GB大小,多了就得处理并且去覆盖,物理日志

不要也可以,但是为了保证持久性,所以每次数据的改变都需要去刷盘,会产生大量的随机IO,对性能影响很大。

有三个重要的指针

更新指针 redolog buffer写入的最新位置

刷盘指针 redolog buffer已经刷盘的位置

脏页指针 是指 buller poll 那些脏页已经成功刷盘的最新位置

redolog buffer恢复的的时候重放之前的修改,就可以恢复,再根据每个事务的状态来决定是提交还是回滚

binlog(复制\备份+恢复)

server层特有的 逻辑日志

binlog日志当写满一个日志文件之后,会新建一个新的日志文件。

写入机制:事务的执行过程中先把日志写到binlog cache中,事务提交的时候再写到binlog文件中。

一个事务的bin log是不可以给拆开的,无论事务多大都要保证一次性写入(这也是大事务造成主从延迟的主要原因)

每个线程都会有自己的binlog cache 但是共用一份binlog文件(参数 binlog_cache_size 默认是8MB)

  • 数据更新步骤 将id=1改为id=2
  • 先将id=1信息写到回滚的 undo log中
  • 在根据 redo log配置,写到 redo log
  • 数据变化SQL写入到binlog日志给与子库同步数据
  • 事务提交
  • redo log和bin log 才可以保证关系型数据库的ACID特性

innoDB和MyISAM的区别

Myisam(256TB)不支持事务操作、不支持MVCC、支持表锁不支持外键,非聚簇索引。适用于select为主的数据库

Innodb(64TB)支持事务操作、支持MVCC、支持表锁和行锁和聚簇索引(也有非聚簇索引),适用于大量的insert和update操作(高并发)

区别:聚集索引的数据跟索引是放在一起的,非聚集索引是分开的

非聚簇索引:索引文件和数据文件是分开的,按照插入的顺序存储在磁盘上。叶子节点存放的数据记录的行指针。

总结一下,MyISAM 引擎中索引查询的步骤为,先按照 B+ 树查询到叶子节点,如果指定的键值存在,则取出其对应的行指针的值,然后通过行指针,读取相应数据行的记录。

聚簇索引:innoDB的数据文件本身就是索引文件,叶子节点的键值就是表的主键。聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。

聚簇索引的叶子节点都包含主键值,事物id,用于事务MVCC回滚。

结论:

  • 聚簇索引:通常由主键或者非空唯一索引实现的,叶子节点存储了一整行数据
  • 非聚簇索引:又称二级索引,就是我们常用的普通索引,叶子节点存了索引值和主键值,在根据主键从聚簇索引查

为什么MyISAM比InnoDB快

1.MyISAM只缓存了索引块,减少缓存换入换出的频率

2.MyISAM是非聚簇索引,innoDB是聚簇索引,innoDB的二级索引需要回表查询,而MyISAM所有索引直接指向数据行存储的位置

3.innoDB还要维护MVCC一致;虽然场景没有但是它还是会去检查,MyISAM表锁牺牲了写性能,提高了读性能

数据库的锁

行锁:粒度小,加锁慢,不容易冲突

页锁:加锁的粒度和时间处于行锁和表锁之间,会出现死锁

表锁:粒度大,加锁快,容易冲突

行锁

行锁都是锁在索引上的,如果要锁的列没有索引,会进行全表记录加锁,如果锁的是二级索引,那么一般情况是下是先锁二级索引再锁聚簇索引

  • 临键锁(Next-key Lock):Record Lock+Gap Lock,锁定一个范围(前开后闭),包含记录本身。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁。(记录锁+间隙锁)

临键锁是innoDB的最基本锁单位,某种情况下回退化为记录锁或者间隙锁

  • 记录锁(Record Lock):也被称为记录锁,属于单个行记录上的锁。解决脏读,重复读
  • 间隙锁(Gap Lock):锁定一个范围(双开区间),不包括记录本身。(解决幻读,在事务隔离级别为可重复读的时候生效)

如果要锁id=6的记录,发现记录不存在的时候就会锁定所在区间,避免区间有新的记录插入

  • 意向锁:当我们想加表锁的时候需要先去判断每一行是否有行锁,复杂度就会很高。我们可以在加行锁的时候在表级别加上意向锁。在意向锁中只有表级的共享锁和行的共享锁会兼容,其他都会互斥。表锁之间的意向锁都兼容

排它锁(X锁)和共享锁(S锁).

事务对数据加X锁的时候,只能本身事务读取和修改

事务对数据加S锁的时候,其他事务只能对数据加S锁不能加X锁,直到事务释放S锁

S锁也称为读锁

场景


待消化


案例三:主键索引范围锁


死锁:

  • t1时刻:T1事务select加锁过程:默认加NextKey(临建锁)锁,但id=3不存在,退化为GAP锁
  • t2时刻:T2事务同样select获取到GAP锁,因为GAP锁是共存锁
  • t3时刻:INSERT加锁过程:因为其他事务有GAP锁,需要加插入意向锁,等待T2释放
  • t4时刻:因为其他事务有GAP锁,需要加插入意向锁,等待T1释放,死锁
  • T1事务在等待插入意向锁,T2拥有GAP X锁,同样等待插入意向,导致死锁吗,选择T2进行回滚(选择行锁数量少的事务进行回滚)

(129条消息) 深入MySQL死锁场景_TechingOn的博客-CSDN博客_mysql死锁场景

索引的分类

  • 主键索引:唯一的标识,主键不可重复
  • 唯一索引:可以有多个唯一索引
  • 联合索引:可以覆盖多个数据列
  • 普通索引:index、key来标识
  • 全文索引(FullText):快速定位数据

原则:小数据量不要加索引,索引一般加载常用来查询的字段上,索引不是越多越好。

MySQL每次只使用一个索引,与其说 数据库查询只能用一个索引,倒不如说,和全表扫描比起来,去分析两个索引 B+树更耗费时间,所以where A=a and B=b 这种查询使用(A,B)的组合索引最佳,B+树根据(A,B)来排序。

说一下innoDB的索引结构

Hash索引(适用于等值查询),b+树索引(适用于范围查询),全文索引,空间索引

索引的好处和坏处

好处: 1.提高数据的检索效率,降低数据库的io成本。

                2.减低数据的排序成本。

缺点:1.占用物理存储空间。

           2.随着数量量的增大,索引的维护成本也随之增大。

           3.发生数据的修改操作时,需要维护。

为什么索引结构默认是b+树索引 *

  • hash:虽然可以快速定位,但是没有顺序,io复杂度高
  • 二叉树:树的高度不均衡,不能自平衡,查找效率不高
  • 红黑树:树的高度随着数据量的增加而增加,io代价大
  • B+树:节点间是有序的,可以存取多个数据。叶子节点之间存储其他的节点,方便全表扫描

B树跟B+树

B树是一个节点可以存储多个数据的,而且数据已经排序。

B+树拥有B树的特点,叶子节点之间存在指针,叶子节点存了所有的元素的,而且排好序。(适用于范围查找,查找效率稳定)

B树

B+树

为什么官方建议使用自增长主键作为索引。 

结合b+树的特点,自增逐渐是连续的,每次插入都是插入到最后,减少分裂和移动的频率。

索引的查询原理

c1和c2都是索引列的情况下,优化器只会选中其中一个作为查询条件,比如在二级索引通过c1=1过滤出两条记录,得到两条数据的主键1和2,然后再去回表查询两行记录,最后在server层过滤c2=1的记录

大部分情况下MySQL只会使用一个索引列 联合索引解决

怎么去识别我们写的SQL有没有走索引

在查询sql前面加一个explain

type 性能类型

possible_keys sql查询可能使用的索引

key sql查询实际使用的索引

key_len 索引的长度,原则上越短越好

Extra sql执行分析

使用索引的注意事项

MySQL每次只使用一个索引,与其说 数据库查询只能用一个索引,倒不如说,和全表扫描比起来,去分析两个索引 B+树更耗费时间,所以where A=a and B=b 这种查询使用(A,B)的组合索引最佳,B+树根据(A,B)来排序。(where b=0 and a=1 底层的优化器会让其走索引)

  • 主键,unique字段
  • 和其他表做连接的字段需要加索引
  • 在where 里使用 >, >=, = ,
  • 使用不以通配符开始的like,where A like ‘China%’
  • 聚合函数里面的 MIN(), MAX()的字段
  • order by 和 group by字段
  • 索引列较长的截取变量部分,独立列进行存储,比如说手机号可以将末尾六位(只要唯一)作为索引

索引失效

  • 搜索一个索引而在另一个索引上做 order by, where A = a order by B,只会使用A上的索引,因为查询只使用一个索引。
  • 联合索引(abc)只能通过条件a、ab、ac、abc
  • 字符串不加单引号(类型隐式转换)
  • or前后两个条件,只要一个没有索引就会失效.
  • 尾部模糊查询,索引不会失效,头部模糊查询会导致索引失效(覆盖索引除外)
  • 索引列有运算或者使用了函数,函数upper()等,or、! = (<>),not in 等

索引下推

简称ICP,也就是把查询中使用索引有关的查询条件下推到存储引擎中。索引条件下推是为了减少回表次数,也就是减少IO操作

SELECT * from user where name like '陈%' and age=20

按最左前缀原理5.6之前是需要做两次的回表 先是根据name查询得到id,再根据id去做一次age的回表查询

5.6之后在索引的内部(server层)就判断看age是否等于20,不等的直接跳过,只需要回表一次

MVCC

MVCC 是一种多版本并发控制,为每一次修改都保存了一个版本基于undo版本链+ReadView来实现的

原理:我们保存在数据库的每条字段都有两个隐藏的字段,一个是trx_id(事务id)和roll_pointer(指向更新这个事务之前的undo log)Undo log版本链:

ReadView机制:

 

事务

事务具有原子性、一致性、隔离性、持久性(ACID)

  • 原子性(undolog记录需要回滚的数据信息)、一致性:要么都执行,要么都不执行回滚。
  • 一致性:基于其他三大特性实现的
  • 隔离性:一个事务的执行不能受其他事务的干扰基于行锁和MVCC(多版本并发控制)
  • 持久性(redolog记录修改时的日志数据):一但提交数据库中的数据就会永久改变

事务带来的问题:

脏读:读取到其他事务(修改)未提交的数据,称为脏数据

丢失修改:指一个事务修改的同时另一个事务也进行修改,会导致第一个事务修改的结果丢失。(乐观锁)

不可重复读:指一个事务多次读取同一数据,读取的期间有人修改了数据会导致数据不一致的问题。

幻读:一个事务在读取表的数据的同时,有另一个事务插入了数据,事务1发现多了之前没有查询到的数据,好像发生了幻觉一样。

事务的隔离级别:

读未提交:允许读取未提交的数据,导致脏读、幻读、不可重复读

读已提交:允许读取已提交的数据,可以阻止脏读

可重复读: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读

序列化: 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。(临建锁解决幻读)

innodb是怎么解决幻读的

将隔离性调到串行化

主要是靠临建锁解决的幻读,第一次读和第二次读的数据不一样就是幻读,调整到串行化后,所有的读都会加共享的临建锁。

分布式事务两阶段加锁(提高并发)

在一个事务里边只有在提交(commit)/回滚(rollback)是在解锁,其余的时间都是在加锁阶段。

对于数据库来说着两个方案的结果都是一致的

但是根据时序可以看出方案二锁住库存的时间更短,库存作为热点,将其放到最后会大大的提高并发,减少库存表锁的时间

避免死锁:产生的原因就是加锁顺序不一致导致的

(125条消息) Mysql事务隔离机制jerry_dyy的博客-CSDN博客mysql事务隔离机制

规范

表规范:单表行数超过500万行或者表容量超过2GB进行分库分表

分库分表:水平拆分就是一表-->维度区分多表、多库 垂直拆分就是表-->字段区分多表、多库

索引列较长的截取变量部分,独立列进行存储,比如说手机号可以将末尾六位作为索引

sql调优

深度分页时,需要注重分页效率,偏移量过大时加上where子查寻提高效率

例如:分页从第1000条开始直接分页查询效率会比较慢,

加上where id>1000 order by id limit 0 10

count(*) ≈ count(1) > count(id) > count(普通索引列) > count(未加索引列)

优化order by效率,建立联合索引

连表尽量使用join 优化器会有限选择小表

group by会默认排序,如果不需要排序就加上order by null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值