mysql与redis面试必问题目
2022-06-07 15:23:56 1 举报
AI智能生成
面试必问的基础问题,面试前可以提前查看,可以克隆自己继续总结
作者其他创作
大纲/内容
Mysql
基础知识
锁
表锁
不会出现死锁,发生冲突几率高,并发低
行锁
会出现死锁,冲突低,并发高
行锁必须要有索引才能实现,否则会自动锁全表
两个事务不能锁同一个索引
insert、delete、update在事务中都会自动默认加上排它锁
两个事务不能锁同一个索引
insert、delete、update在事务中都会自动默认加上排它锁
间隙锁
当使用范围条件时,并且使用的是排它锁,InnoDB会给符合条件的记录的索引添加锁,上一个事务未提交的话,会阻塞直到上一个提交事务
意向锁
意向锁是一种不与行级锁冲突表级锁
意向共享锁(intention shared lock, IS):事务有意向对表中的某些行加共享锁(S锁)
意向排他锁(intention exclusive lock, IX):事务有意向对表中的某些行加排他锁(X锁)
上锁
上共享锁(读锁):lock in share mode
上排它锁(写锁):for update
三范式
确保每列原子性约束,不可再分
唯一性表只有一个主键
满足第二范式,并且表中的非主键列依赖主键
索引
InnoDB
它是Mysql默认的事务型存储索引,采用了MVCC来支持高并发,并且实现了四个标准的隔离级别,默认是可重复读。
主索引时聚簇索引,在索引保存了数据,从而避免了直接读取磁盘。
支持真正的在线热备份,mysql其他的存储引擎不支持在线热备份。
主索引时聚簇索引,在索引保存了数据,从而避免了直接读取磁盘。
支持真正的在线热备份,mysql其他的存储引擎不支持在线热备份。
InnoDB的B+Tree索引分为主索引和辅助索引。主索引的叶子节点data域记录完整的数据记录,这种索引也就是聚簇索引。
辅助索引的data域记录着主键的值,因此使用辅助索引查询时要先找到主键值,然后再到索引中进行查找,这个过程叫做回表。
辅助索引的data域记录着主键的值,因此使用辅助索引查询时要先找到主键值,然后再到索引中进行查找,这个过程叫做回表。
覆盖索引:其实覆盖索引就是为了解决使用非聚簇索引进行查询提高查询效率,避免了回表查询
MyISAM
设计简单,对于只读数据,或者小表,可以容忍修复操作依然可以使用。不支持事务,不支持行级锁。
B+Three
是B树的一种变形,它是基于B Tree和叶子节点顺序访问指针进行实现的,通常用于数据库和操作系统的文件系统中
索引的优点
索引使用的条件
对于非常小的表,大部分情况下简单的全表扫描比简历索引更高效,还有隐含条件不是索引构成部分,不需要回表,而且查询条件也不是主键。
对于大中的表,索引就非常有效
但是对于特大型表,建立索引和维护索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录德地址,例如可以使用分区技术
调优
调优过程
在开发时写的sql会用explain去看一下执行计划
在mysql8.0之前要排除缓存的干扰,因为一些静态表没有进行更新过,数据存在缓存中,会发现查询速度很快,可以添加配置,也可以在sql里加入SQL_NO_CACHE
使用覆盖索引减少回表查询,提高性能
联合索引,不要查出id之后去回表查询库存数
explain分析
关键字
select_type
常用有SIMPLE简单查询,UNION联合查询,SUBQUERY子查询等
table
查询的表
possible_keys
可选索引
key
实际使用的索引
rows
扫描的行数
type
索引查询类型
const
使用主键或者唯一索引进行查询的时候只有一行匹配
ref
使用非唯一索引
range
使用主键、单个字段的辅助索引的最后一个字段进行范围查询
index
扫描的索引树
all
扫描全表
调优方式
会重建表开始考虑,创建的字段数据类型是否合理,遵循选取数据类型越简单越小原则
字段能使用数字类型的时候就不要使用字符串,因为在扫描的时候字符串需要一个个对比,而数字只需要对比一次,性能会好一些
字段长度的限制也是能够满足的前提下尽可能的小。可以减少资源的消耗
索引创建不是越多越好,越多会浪费相应的资源空间。当表很小的时候可以不需要创建索引,全局扫描更快,但是这里不包括说主键。
还有频繁更新的,唯一性差的,where中不用的字段不建议创建索引
在平时开发时候使用到的sql查询语句我会使用explain分析查询语句是否走索引,走的索引类型等问题来进行优化
注意一些回表查询使得效率低下的原因,可以使用覆盖索引、联合索引方式避免
注意一些索引失效的例子,最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(<,>,BETWEEN,LIKE)就停止。
索引列不要作为参数计算,尽量保持列‘干净’
MVCC和事务隔离
事务
ACID
原子性
事务要么全部成功要么全部失败
一致性
所有事务对一个数据的读取结果都是一样的
隔离性
一个事务所作的修改最终提交以前,对其他事务是不可见的
持久性
所做的修改将会永远保存到数据库中
实现保证
mysql的存储引擎InnoDB通过重做日志保证了持久性与一致性,回滚日志保证了原子性,各种锁保证了隔离性
隔离级别
未提交读(READ UNCOMMITTED)
一个事务还没提交,它做的变更其他事务能看到
最低的隔离级别,能够读取到未提交的数据,会出现脏读、幻读、不可重复读
提交读(READ COMMITTED)
一个事务提交后,它做的变更其他事务才能看到
允许读取并发情况下的提交数据,能够阻止脏读,但还是会出现幻读、不可重复读
可重复读(REPEATABLE READ)
保证同一事务中多次读取数据结果一致
重复读取一个数据结果一致,能够解决脏读,不可重复读问题,如果数据被本身事务所修改,还是会出现幻读
可串行化(SERIALIZABLE)
需要加锁实现,强制事务串行执行
事务都是按顺序执行,事务之间不回产生影响
MVCC
理解
所谓MVCC说的是多版本并发控制,指的是再使用读已提交、可重复读着两种隔离级别在执行select操作访问记录得版本链得过程,这样可以使不同事务得读-写、写-读操作并发执行,从而提升系统性能。
InnoDB的MVCC,是通过在每行记录后面保存系统版本号(可以理解为事务的ID),每开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID。这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的,防止幻读的产生
问题
启动事务
显示启动事务语句:begin或 start transaction,配套的提交语句是commit,回滚是rollback
如何解决幻读
隔离级别设置可串行化,但是性能下降很多
使用MVCC解决快照幻读问题(普通的查询都是快照读,其他都是当前读),
分库分表
分表方案
原因
分表应用场景是单表数据量增长速度过快,影响了业务接口的相应时间。如果表平均长度太大,就是字段太多,需要进行垂直分表,如果是表的记录太多了,就水平分表
垂直分表
将频繁使用到的字段放一张表,频繁低的放在另外一张表
水平拆分
前提,单表不建议超过500w数据量
看场景可以进行不同的区分,如订单表,我们可以使用用户id,或者月分来分,
分库方案
原因
mysql的高可用架构大多都是一主多从,所有写入操作都发生在Master上,随着业务的增长,数据量的增加,很多接口相应时间很长,而且通过升级MySQL实例配置也无法解决问题,着时候就需要分库,通常两种做法:按业务拆库和按表分库
按业务分库
按表分库
主从库
原理
主库db的更新事件(update、insert、delete)被写到binlog
主库创建一个binlog dump thread线程,把binlog的内容发送到从库
从库创建一个I/O线程,从主库读取的内容写入到 relay log
从库还会创建一个sql线程,从relay log里面读取内容写到slave的db
Redis
基础知识
为啥使用redis?
传统的关系型数据库mysql已经不能适用与所有的场景了,比如秒杀的库存扣减,app首页访问流量高峰等等,很容易将数据库打崩,所有引入了缓存中间件,目前市面常用的有redis和memcached。
与Memcached相比,
redis采用单线程模式处理请求,原因一个是因为采用了非阻塞的异步事件处理机制,另外一个是缓存数据都是内存操作io时间不会太长,单线程避免了线程上下文切换的代价。
redis支持持久化,也可以当作NoSql数据库使用。
redis还提供了多种数据格式来使用。
redis提供了主从同步机制,以及Cluster集群部署能力,能够提供高可用服务
redis采用单线程模式处理请求,原因一个是因为采用了非阻塞的异步事件处理机制,另外一个是缓存数据都是内存操作io时间不会太长,单线程避免了线程上下文切换的代价。
redis支持持久化,也可以当作NoSql数据库使用。
redis还提供了多种数据格式来使用。
redis提供了主从同步机制,以及Cluster集群部署能力,能够提供高可用服务
内存操作数据为什么比磁盘快??
因为磁盘是有机械机构,磁头要运动到相应的位置,转片还在转动,然后读取磁信号
内存没有机械机构,它就是电,瞬间到达。电的到达速度要比磁头的运动快得多,比盘算转动也快得多。所以,有机械结构的磁头的读取速度是不能和无机械结构电的速度相比的。
内存,一般分为RAM、ROM和高速缓存三大类。
硬盘,一般分为机械硬盘和固态硬盘。固态硬盘使用的是闪存,比机械硬盘的磁盘要快得多,但也不能和真正的RAM去比速度。
redis有那些数据结构?
String、Hash、List、Set、SortedSet,高级玩家还有HyperLogLog、Geo、Pub/sub
如果还想加分,说还玩过REdis MOdule,如BloomFilter(布隆过滤器)
如果还想加分,说还玩过REdis MOdule,如BloomFilter(布隆过滤器)
如果大量key设置同一时间过期需要注意什么?
如果key过期时间过于集中,到货期时间点,Redis可能会出现短暂的卡顿现象,严重出现缓存雪崩。我们可以在时间上加一个随机值,使得过期时间分散一些
redis的事务知道么?
不是严格的事务,只能保证串行执行命令,并且能保证全部执行,但是命令失败不会回滚,会继续执行下去
如何持久化
RDB
概念
默认持久化方案;是以快照的形式保存数据的结果;存储格式简单;
RDB把整个redis数据保存在单一文件中,比较适合用来做灾备,但是缺点是快照保存完成之前如果宕机这段时间的数据会丢失,另外保存快照时可能会导致服务段时间不可用。
优缺点
数据恢复快;不安全,容易丢失数据;
实现方式
save命令 ---- 会阻塞当前进程,影响项目运行。
bgsave命令 -----新开一个线程去执行数据保存任务。不影响项目运行。
配置文件 ------自动触发bgsave方式去保存数据。
和AOF两种持久化方式
概念
日志追加形式;保存的是数据的操作过程;依靠重新执行AOF文件中的命令来实现数据恢复;
AOF对日志文件的写入操作使用的追加模式,有灵活的同步策略,支持每秒同步,每次修改同步和不同步,缺点时相同规模的数量级,AOF要大于RDB,效率低于RDB
优缺点
数据安全性较高,不易丢失数据; 效率低,数据量大,恢复数据慢;
实现方式
备份方式: 配置文件开启AOF方案,并指定保存策略;
为什么Redis这么快
Redis采用的是单进程单线程模型的KV数据库,QPS可以达到10万
完全基于内存,大部分请求时纯粹的内存才做非常开快。
数据结构简单,是专门进行设计的数据结构。
蚕蛹单线程,避免的不必要的上下文切换和竞争关系。
使用多路I/O复用模型,非阻塞IO;
数据结构简单,是专门进行设计的数据结构。
蚕蛹单线程,避免的不必要的上下文切换和竞争关系。
使用多路I/O复用模型,非阻塞IO;
I/O多路复用?
其实就是可以让单线程高效的去处理多个连接请求
IO多路复用其实就是一种同步IO模型,它实现了一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;而没有文件句柄就绪时,就会阻塞应用程序,交出cpu。
淘汰策略
先进先出算法
最近使用最少
最常时间未使用
过期策略
定期删除
将设置了过期时间的key放入一个独立的字典里,默认没100ms进行一次过期扫描
常见问题
缓存雪崩
大量key设置同一过期时间,这个时间点大量请求过来,可能就会把redis打崩。
解决办法就是失效时间加一个随机值,让过期时间分散一些。
如果redis是集群部署可以将热点数据均匀放在不同的redis库中,避免全部失效。
也可以设置热点数据永不过期,当有更新就跟新缓存就好了。
如果redis是集群部署可以将热点数据均匀放在不同的redis库中,避免全部失效。
也可以设置热点数据永不过期,当有更新就跟新缓存就好了。
缓存穿透
是指缓存和数据库都没有这个数据,而用户不断发起请求,有可能是攻击者,这样请求会直接打到数据大,压力过大可能就会将数据库打崩
我会在接口层增加校验,比如用户鉴权校验,参数校验,不合法的参数直接return。
在缓存和数据库都取不到的值,我们可以将对应的key的value写为null,设置一个30秒的失效时间。
或者在Nginx有配置,对单个ip每秒访问次数做一个限制
在缓存和数据库都取不到的值,我们可以将对应的key的value写为null,设置一个30秒的失效时间。
或者在Nginx有配置,对单个ip每秒访问次数做一个限制
布隆过滤器也可以很好的防止穿透发生。它的原理就是利用高效的数据结构和算法快速判断这个key是否在数据库中存在,不存在直接return。
缓存击穿
击穿是指一个key非常热点,在不停的扛着大并发,当这个key失效瞬间,持续的大并发就击破了缓存,直接请求了数据库。
设置永不失效,或者加上互斥锁就能搞定
布隆过滤器
理解
布隆过滤器时一种数据结构,是由一串很长的二进制向量组成。布隆过滤器可以用于检索一个元素是否存在一个集合中,它的有优点是空间效率与查询时间都远远超过一般的算法,缺点是有一定的误判率和删除困难。
它的原理是:当一个元素被加入集合时,通过k个散列函数将这个元素映射成一个位数组中的k个点,把它们置为1.检索时这些点都1说明它可能存在集合中,如果有一个0则不存在。
使用
Redis实现布隆过滤器的底层就是通过bitmap这个数据结构。可以直接使用Redisson。它是java程序中操作Redis的库。
秒杀系统
分布式锁
为什么需要分布式锁?JVM不是提供了很多解决并发问题的工具么?
现在基本上都是集群方式,此时Synchronuzed就不起作用了,此关键字的作用域是一个进程,但是多进程的时候还是出现问题。所有为解决集群时候数据一致性的问题,我们会考虑使用分布式锁来解决问题。
为什么选择了redis做分布式锁?
集群
主从复制
哨兵模式
Redis-Cluster集群
redis在3.0上加入了cluster模式,实现了redis的分布式存储,也就是每台redis节点上存储着不同的内容
常用操作
String
是Redis最常用的类型,内部实现通过SDS来存储,SDS类似java中的ArrayList,使用就是set和get
可以做缓存功能、计数器、共享用户session
Hash
类似于Map一种结构,这个一般就可以将结构化的数据,把一个对象保存在redis里
List
是有序列表,可以存储一些列表型的结构,如粉丝列表、文章的评论列表这类东西。
当消息队列
Set
是无序集合,会自动去重那种
Sorted Set
是排序的Set,去重并排序
收藏
收藏
0 条评论
下一页