2026.4.27 第五篇

MySQL的ACID怎么保证?

原子性:通过undo log来实现,在修改数据之前记录旧值,事务回滚的时候根据undo log执行与之相反的操作即可。

  • 注意:事务回滚后undo log并不会被清除,而是确保undo log不再被事务使用的时候才会清除 持久性:主要依赖redo log + WAL机制和CheckPoint机制来实现
  • WAL即修改bufferpool 中的数据后先将修改写入到redo log中,然后找机会刷新到磁盘上。
  • 将 buffer pool 中的脏页刷新到磁盘记录当前刷盘位置(LSN) 隔离性:通过锁和MVCC(多版本并发控制)实现 一致性:事务执行前后数据满足约束,由原子性、隔离性、持久性共同保证

mysql崩了怎么保证持久性

MySQL 通过 redo log + WAL 机制保证事务提交时日志先落盘,崩溃恢复时通过重放 redo log 恢复数据,从而保证持久性。

单例模式(双重检测锁)

class Singleton{
	private static volatile Singleton instance; //禁止指令重排防止获取还未实例化的对象
	private Singleton(){}
	public static Singleton getInstance(){
		if(instance == null){ //如果已经实例化了就不用再获取锁了,提高性能
			synchronized(Singleton instance){
				if(instance == null){ //防止多个线程同时通过第一次判空,在排队拿锁后重复创建对象
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

为什么加volatile?

防止对象的创建被指令重排,获取到还未实例化的对象

  1. 分配内存
  2. 初始化对象
  3. instance 指向内存
    如果没有 volatile,可能变成:
    1 -> 3 -> 2
    导致其他线程拿到“未初始化完成”的对象

Volatile的实现原理

volatile写会在volatile写后面加Store内存屏障 volatile读会在volatile读前面加Load内存屏障

为什么 volatile 写只在后面加 Store 屏障不在前面加?为什么 volatile 读只在前面加 Load 屏障不在后面加?

写前如果加屏障,是防止:volatile 写 → 跑到前面,但: JMM 本身就不允许“写往前越过前面的代码”破坏程序顺序 读后屏障是防止:volatile 读 → 跑到后面,但: 读本身不会影响其他线程 因此:

  • volatile 写通过写后屏障,保证之前的写对其他线程可见;
  • volatile 读通过读前屏障,保证之后的读不会读取到旧值;
  • 只加一侧屏障是因为只需要保证 happens-before 的单向约束,避免不必要的性能开销。

SQL优化

这个表数据量500w条,满足 seller_id=12345678 的数据量1500条,查询比较慢(>100ms) ① 分析原因
② 解决方案

CREATE TABLE `t_seller_count` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `dt` varchar(32) NOT NULL COMMENT '统计日期',
  `seller_id` bigint(20) NOT NULL COMMENT '卖家id',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  `pay_order_num` int(11) DEFAULT NULL COMMENT '支付订单数',
  `complete_order_num` int(11) NOT NULL COMMENT '完成订单数',
  `apply_refund_num` int(11) DEFAULT NULL COMMENT '退款订单数',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_seller` (`seller_id`, `dt`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='卖家订单统计表';
select sum(complete_order_num)  
from t_seller_count  
where seller_id = 12345678;

为什么慢?

使用了索引但不是覆盖索引,会回表 注意:索引是否生效,核心看的是“是否参与查找(过滤 / 定位 / 排序 / 分组),索引失效通常发生在 where 条件里(join两个不同编码格式的表导致的隐式字符转换)。这里的sum()是对结果进行聚合。

1. 对索引列做函数/运算

where seller_id + 1 = 123

2. 隐式类型转换

where seller_id = '123'   -- 字符串 vs bigint

3. 违反最左前缀原则

index(a, b, c)  
where b = 1   -- a 没用 → 失效

4. 范围查询后断裂

where a = 1 and b > 2 and c = 3  
-- c 用不到索引

解决方案

优化方式是建立覆盖索引:

ALTER TABLE t_seller_count  
ADD INDEX idx_seller_complete_order_num (seller_id, complete_order_num);

SQL语句的书写顺序

SELECT
    列名,
    聚合函数(列名)
FROM
    表名
JOIN
    关联表 ON 关联条件
WHERE
    行过滤条件
GROUP BY
    分组字段
HAVING
    分组后的过滤条件
ORDER BY
    排序字段
LIMIT
    分页数量;

跳表为什么快?

跳表通过多层索引结构,使查找时可以跳跃式前进,
将时间复杂度从 O(n) 降到 O(log n),这是其性能高的根本原因。
相比红黑树,跳表实现简单,且天然支持范围查询。

RDB怎么写入?

RDB 通过 fork 子进程生成内存数据的快照文件,

子进程遍历内存并写入 RDB 文件。

在生成过程中,主进程通过写时复制(COW)机制保证数据一致性,不会阻塞读操作。

RDB 不记录增量日志,只保存某一时刻的全量数据。

Redis的 COW(写时复制)

和Java的CopyOnWriteArrayList一样

只有在主进程发生写操作时,才会复制对应的内存页进行修改。

为什么Cluster集群的分片为什么是16384个槽?

Redis Cluster 采用 16384 个槽,是在数据分布均匀性和集群通信开销之间的权衡。

槽数量足够多,可以保证数据分布均匀、迁移粒度细; 同时又不会太多,使得节点之间通过 bitmap 同步 slot 状态时开销较小(约 2KB)。

此外 16384 是 2 的幂,便于通过位运算快速计算 hash slot。

Cluster 集群

Redis Cluster 是 Redis 的分布式方案,用于解决单机内存瓶颈和高可用问题。 Redis Cluster 通过 16384 个 hash slot 实现数据分片, 每个节点负责一部分 slot,客户端通过计算 key 的 slot 直接路由请求。

集群采用主从结构实现高可用,主节点宕机后从节点自动提升, 节点之间通过 gossip 协议同步状态。

相比一致性哈希,slot 机制使得扩容和数据迁移更加灵活。

请求是怎么路由的

计算 key 的 slot
2. 找到对应节点
3. 直接访问该节点 如果访问错节点:Redis 返回 MOVED 重定向

怎么排查慢sql?

  1. 开启slow log
  2. 使用MySQL自带的工具,比如mysqldumpslow 对慢日志进行排序,找执行次数多且执行慢的SQL
  3. 使用explain获取执行计划
  4. 判断原因(可能是没有索引、索引失效、选错索引)
  5. 优化:加索引、改 SQL、覆盖索引、分页优化、缓存
#面经#
每日面经记录 文章被收录于专栏

记录每天Java和Agent面经学习

全部评论

相关推荐

1.OK你给我讲一下这两个题的一个你做的一个思路。(括号匹配,反转链表)2.他的时间复杂度是什么样的?3.OK,面试题就到这里,然后你先简单自我介绍一下。4.有关的登录注册和优惠券的一个模块吗?OK你这里面有一些高并发的场景是吗?你讲一下整个系统的一个高并发场景是怎么设计的。5.是公司的架构还是你当时设计的。6.你从整个公司的架构,然后再到你负责的模块进行详细讲解一下。7.详细介绍一下你做的那个模块。 还有吗?8.你登录是用的JWT对吗?它的token是怎么刷新的?9.这套方案是你设计的吗?还是参考了别人这么设计。10.你一个token跟两个token的区别是什么?它的优点跟缺点是什么?11.你的单头单token,你们最开始的设计方案单token是不刷新的吗?12.你的双头肯的话,你的token数据不暴露在前端吗?去刷新那个token。那你单token不能这么做吗?13.这个方案是你们组内评审的对吧?对你有了解过,你有你有调过微信的相关的一些接口吗?14.然后高并发的话,你大概的一个或者说你们整个项目的一个架构是怎么设计的。我看还保证万QPS0超发,就从整个架构。从前端用户进来,然后到你的服务器,然后到你的数据库。15.用那个唯一的,索引是吧,你这个有多少台服务器。16.你的数据库mysql的配置是什么样子的?推荐当时评审的时候你有参与吗。17.那你的你这样子直接操作库的话,你的数据库如果被打死了怎么办?比如说你真的到万qps对吧?然后你可能如果到后面的话,你的流量越大,然后你的慢收口会越来越多。你的数据库已经处理不过来了,然后数据库打死了怎么办?18.那你查询躲不掉,你还有其他方法去判断这个用户有没有领过吗?19.慢查询的优化,一般的话慢射口是怎么优化的一个过程。然后索引失效的话,一般有哪一些方式会导致索失效,然后要怎么处理?20.mysql创建索引的语句,你口述一下。创建一个唯一索引。21.行,OK, 那我看一下你的你当时做的慢的优化主要是做什么东西?22.行,OK, 然后我再看一下。我看你有做过一些AI的东西,对吧?你这个是做了一个什么样的项目?你那个AI助手。23.OK,我这边暂时没有别的问题了,看看你有没有什么想对我们这边了解。还有一个就是你是哪里人?24.反问:25.评价1:怎么评价?首先我觉得你的那个题做的非常好啊,然后也做的很快,甚至你都没有花15分钟,而且思路也比较清晰。我感觉你自我介绍的时候,就是没把你的一些优势介绍出来。比如说你拿过很多程序设计的大赛的奖,对吧?你都没有讲。因为这是对于学生来说的话,这是你的优势。你们很多同学应该是没有拿过这个奖的。25.评价2:对你要把你的优势介绍出来。然后你的那个经历,我看你简历上那个经历,从25年8月到26年2月,这下面是空的,然后后面又是26年2月到至今。但是这里在这个莲雾自在的这个公司里面,它是有一些信息的。所以我前面问你我说不知道你在上面做了啥,然后得去看你下面的项目经验,而且你的项目经验又没有写时间,就是我不知道你的项目是在哪个公司做的,所以我就只能来问你。26.评价3:对,然后回答问题我觉得你可以简洁一点,就不要说太多了。尽量的话因为我们都是做技术的,不要跟人讲太多的业务。实施业务的话可能别人也不是很关心,你就讲整个是中间是怎么实现的,就纯讲技术就好了,我是这么想的,对。27.一周左右,我要把你的信息综合跟其他的一些面试者进行PK然后再综合给到评估,看谁能进下一轮。因为你这里的话是前面做了个笔试对吧?这是今天是第一次面试,然后总共是有四轮。对,今天才第一轮。对,所以周期会比较长,基本上每一轮都是在一周左右的时间会有一个反馈。然后这里可能觉得有一个五一了,可能要到51之后。结果。
查看22道真题和解析
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务