八股总结(数据库)实时更新!
八股总结(数据库)
-
Redis的持久化有哪些方式?
-
RDB (默认),通过二进制格式的数据快照保存数据到磁盘;
- 回复速度快,且内存小
- 但RDB是定期快照,不是实时保存
-
AOF,记录所有写数据来持久化数据,类似日志文件;
- AOF数据安全性高,且是文本文件可用于数据分析与调试;
- 但文件体积大,回复速度慢;
-
RDB与AOF混合,在AOF重写时,redis将当前数据快照写入AOF文件开头,之后在重写期间的写操作以AOF格式追加到文件中;
-
-
缓存穿透、缓存击穿、缓存雪崩是什么?
-
缓存穿透,是大量请求查询不存在的数据,不经过redis直接访问数据库;
解决方案:布隆过滤器,同请求缓存空值,参数合法校验;
-
缓存击穿,是热点数据在缓存中过期,导致大量请求同时访问数据库;
解决方案:热点数据永不过期,缓存失效后互斥锁,缓存预热;
-
缓存雪崩,是多个缓存同时过期,导致大量请求同时访问数据库;
解决方案:缓存过期添加随机值,多级缓存,限流降级;
-
-
布隆过滤器的底层原理
- 底层实现基于位数组与多个哈希函数,位数组是长度为m,每个位只能存储1或0,布隆过滤器使用k个独立哈希函数,将输入元素均匀分布到位数组中;
- 添加元素:将元素通过k个哈希函数计算,得到k个哈希值,将位数组对应k个位置设置为1;
- 查询元素:将元素通过k个哈希函数计算,得到k个哈希值,若位数组中所有对应位置都为1,则元素可能存在,任何一个位置为0,则一定不存在;
- 特点:空间效率高,查询速度快,有一定误判率;
-
MySQL的隔离级别是什么?可重复读的特点是什么?能否解决幻读?
-
读未提交,读已提交,可重复读,串行化;
-
可重复读的特点是在同一个事务中读取同一个数据是一致的(MVCC,为每个事务创建一个快照);
-
幻读是多次查询同一范围的数据时,数据行数不同,因为其他事务执行了插入或删除;
-
-
MVCC是什么?
- MVCC是多版本并发控制,每条数据都会有多个版本,用于记录实际值、创建该事务的ID、创建或删除该版本的时间戳、指向Undo log的指针;
- 每条事务在开始执行前都会分配一个事务ID与时间戳,事务只能看到在他之前已经提交的数据版本与自身修改的数据;
- 优点:高并发,读写操作不会互相阻塞;一致性读,事务可以看到一直的数据快照;减少锁冲突,通过多版本数据,减少对锁的依赖;
- 缺点:需要存储多个版本的数据,增加了存储空间;需要定期清理过期的旧版本数据,增加系统开销;如果多个事务同时修改同一数据,仍需要加锁;
-
为什么MySQL使用B+树索引结构?
- B+树的适用情景为io数据流的读取,因为其节点可以有多个子节点,每个节点可以存储多个键,用于减少树的高度,降低磁盘io访问次数,并且所有子节点在同一层,用于平衡io的平均访问时间,叶子节点之间通过指针连接,形成一个有序链表,支持高效返回查询;
-
如何判断SQL语句是否命中索引?
- 使用EXPLAIN命令,可以查看查询是否使用了索引
-
Redis分布式锁如何实现?
- 在springboot项目中,使用redis的template的setIfAbsent()方法,进行上锁,需要设置锁名与id及其过期时间;
- 使用redisson库管理分布式锁,手动获取锁与释放锁;
- 执行redis的Lua脚本,手动编写上锁释放锁的代码并运行,Lua保证事务的原子性,避免误删锁;
-
mysql和redis的区别?
- mysql是关系数据库,redis是非关系数据库;
- mysql数据存储再磁盘中,redis数据存储在内存中,但也可以选择持久化存储,例如RDB和AOF两种持久化方式;
- mysql因为要设计磁盘的IO读写所以访问速度相比较与redis基于内存的读写较慢;
- mysql的场景主要是进行复杂的查询与大量数据的存储,而redis是解决高并发与实时数据缓存的场景;
- mysql支持ACID事务,而redis只支持简单的事务,但不支持回滚;
-
mysql事务介绍一下?
- 首先是事务的ACID特性:
- 原子性:事务的运行是不可分割的最小单元,要么全部成功要么全部失败回滚;
- 一致性:事务执行的前后总是由一个有序的状态到另一个有序的状态,数据保持一致的状态;
- 隔离性:事务之间互不影响;
- 持久性:事务一旦执行,数据会永久存储在数据库中;
- 事务的隔离级别:
- 读未提交,事务中读取的数据可能是其他事务修改后但执行了回滚;
- 读已提交,事务中多次读取同一数据,但可能其他事务中间修改,导致读取不一致;
- 可重复读,事务采用MVCC多版本并发控制机制,确保每个事务读取的数据是事务执行前开始的版本;
- 串行化,事务依次执行;
-
Redis 都有哪些集群模式
- 单机模式:只有一个redis实例;
- 主从复制模式:一个主节点负责写操作,多个从节点复制主节点的数据,提供读操作,适用于读多写少的场景,如果主节点故障需要手动切换;
- 哨兵模式:在主从复制模式的基础上,引入哨兵(Sentinel)用于监控主从节点的状态,实现自动故障转移;
- 集群模式:Redis提供的分布式解决方案,将数据分片存储到多个节点,每个节点负责一部分数据,适用于大规模数据存储和高并发访问的场景;
- 代理模式:通过代理将客户端请求分发到多个redis实例;
-
redis集群模式分布式的底层原理
- Redis提供的分布式解决方案,将数据分片存储到多个节点,每个节点负责一部分数据,适用于大规模数据存储和高并发访问的场景;
- 集群将数据集划分为16384个哈希槽,将键通过哈西算法分配给对应的哈希槽,每个节点分配一部分哈希槽;
- 节点之间通过Gossip协议通信,确保集群状态的一致性,每个节点定期随机选择部分其他节点交换信息,确保集群中每个节点最终都能获得全局一致的集群视图;
-
一致性哈希算法?
- 是一种特殊的哈希算法,用于解决分布式系统中的数据分布与负载均衡;
- 将哈希空间组织成一个环,数据和节点都通过哈希函数映射到环上的某个位置;
- 数据通过哈希函数计算哈希值,映射到环的某个位置,从该位置顺时针查找,找到的第一个节点就是该数据的归属节点;
- 当有节点加入或退出指挥影响相邻的节点数据分布,用来减少数据迁移的开销;
-
redis的数据结构底层原理
- String:采用的是SDS动态字符串,三个参数,实际长度,剩余空间,字符数组,当字符串修改时,自动扩展;
- List:当元素较少时,使用压缩列表,元素较多时,使用双向链表;
- Hash:当元素较少时,使用压缩列表,元素较多时,使用哈希表;
- Set:当元素较少且为整数时,采用连续数组存储整数,元素较多时,使用哈希表;
- ZSet:当元素较少时,使用压缩列表,元素较多时,使用跳表;
-
数据库的索引
- 索引是一种数据结构,用于提高数据库查询的效率,加速查询、排序、分组和聚合;
- 索引的类型:
- 主键索引:用于主键的约束,保证数据唯一且不为空;
- 唯一索引:保证某一列的值是唯一的,但是允许null;
- 复合索引:再多个列上创建索引,优化组合查询的效率;
- 全文索引:用于全文搜索,适用于文本内容的检索;
- 哈希索引:基于哈希表实现,查询速度极快,但是不支持范围查询;
- 索引会影响写入性能,比如插入更新删除都需要更新索引,需要占用额外的存储空间;
-
复合索引失效的情况
- 复合索引遵循最左前缀原则,即索引的使用顺序必须按照创建索引时的列顺序;
- 造成索引失效的情况有:
- 索引列使用了函数或者运算符;
- 索引列范围查询;
- 索引开头使用了通配符;
- 索引没有遵循最左前缀原则;
- 查询子句没有全部都使用索引;
- 索引列进行了隐式类型转换;
- 索引列中包含null;
-
B树与B+树
-
B树与B+树都是常见的平衡多路搜索树,用于数据库索引和文件系统;
-
B树每个节点都存储数据和索引,叶子节点与内部节点存放数据,及数据可能存放在不同的层级;
-
B+树叶子节点存储数据,所有叶子结点通过指针相连,形成一个有序的链表;
-
B+树因为数据都由双项链表连接,所以更方便范围查询,B树需要遍历整个树;
-
因为B+树的索引密度更高,所以每个借点内可以融安更多的索引,是树的高度更小,从而减少磁盘的IO,提高查询性能;
-
-
MySQL 乐观锁和悲观锁有什么区别
- 乐观锁假设并发冲突少,只在提交时检测冲突,常通过版本号或时间戳实现,不加所,适用于读多写少、冲突概率低的场景;提交时冲突则需回滚或重试;
- 悲观锁假设并发冲突会频繁发生,在读取数据前就加锁,防止其他事务修改数据,直到当前事务完成,适用于写多读少、确保数据一致性高于并发性能的场景;会阻塞其他事务,降低系统吞吐量;
-
死锁的条件
- 互斥:资源一次只能被一个线程使用;
- 持有并等待:线程已经有一个资源,但还在等待获取其他的资源,同时不释放当前已经持有的资源;
- 不可剥夺:资源不能被强制回收,只能由持有此资源的线程主动释放;
- 循环等待:存在一个循环的资源依赖链,每个线程都在等待下一个线程持有的资源,形成一个环;
-
如何避免死锁
- 破坏循环等待,强制按照固定顺序申请锁;
- 使用超时机制,破坏持有并等待,避免无限等待; -
MySQL 的慢查询如何优化?
- 使用EXPLAIN查询sql语句的执行计划;
- 优化sql语句避免查询所有数据或大量数据;
- 对索引进行优化,建立联合索引;
- 对大数据量的表进行分表;
-
索引为什么能加快查询速度
- 可以快速定位数据,减少数据库扫描的行数,从而提高查询效率;
- 索引使用B+树进行高效查找,B+树是一种平衡多叉树,查询时间复杂度为O(n),远小于全表扫描的O(n);
- 提高排序分组的效率,通过索引可以直接按照索引顺序进行读取数据,无需排序操作;
-
创建索引以哪些字段作为索引,那为什么不能全部字段建立索引
- 首先创建索引适合在热点查询字段上,例如主键外键唯一键上,查询高效。还可以在在热点可排序字段上,避免排序时额外计算;
- 首先索引的创建需要占用额外的空间,并且当数据修改时,需要维护索引占用更多的性能;