拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL面试核心考点全梳理:索引、事务、锁与日志的底层原理

MySQL面试核心考点全梳理:索引、事务、锁与日志的底层原理

金三银四又到了,后台私信里“MySQL面试要复习到什么程度”这个问题突然多了起来。不少朋友手里拿着一摞八股文,背得滚瓜烂熟,可真去大厂面试,往往在第三轮追问时就卡壳。原因很简单:MySQL这块的知识点太散,大家是“记住”了,而不是“理解”了。

这篇是Java大厂面试题系列的第二章,专门聊MySQL。我不会按教材顺序给你罗列知识点,而是按大厂面试官的真实出题逻辑来拆:他们先问什么、追问什么、追问的落脚点是什么,以及每个考点背后到底在考察你的什么能力。内容覆盖索引、事务、锁、日志、主从复制、SQL调优这些高频区间,也会给到一些现场答题的组织方法。适合正在准备校招、社招的Java开发,也适合那些MySQL基础不牢、想系统梳理一遍的同学。

1. 大厂MySQL命题思路:面试官到底在挖什么

先聊一个很多人没想明白的问题:面试官问MySQL,真的只是想确认你会写SQL吗?当然不是。如果只考写SQL,那招个ORM工具使用者就够了。大厂面试官问MySQL,一般隐藏着三个层次的考察意图。

第一层是基础准确度。事务的ACID、隔离级别有哪几种、索引为什么用B+树,这些定义你不能说错。这层考察的是你有没有认真看过书,是不是科班底子。答错基本一票否决,因为它代表你不具备后续讨论的共识基础。

第二层是原理深度。问你“为什么InnoDB用B+树”“MVCC怎么实现的”“redo log为什么能保证崩溃恢复”,是在考察你能不能从机制层面解释现象。这层没有标准答案,面试官听的是你的推理链路是否完整。

第三层是工程意识。这是大厂最爱考的隐蔽层。举个例子,你说“主从复制有延迟”,面试官会接着问“那你怎么保证刚写完就读到最新数据”“读写分离下过期读怎么办”“延迟突然飙升你从哪排查”。这些问题没有书本能直接给出答案,考察的是你有没有真实生产经验,有没有踩过坑。

还有一个值得注意的点:大厂的面试官很少按“索引、事务、锁”这种教科书目录切块提问,他们更爱从一个入口题开始连环追问。比如从“一条UPDATE语句在MySQL里是怎么执行的”开始,一路问到redo log、两阶段提交、崩溃恢复、主从同步、数据一致性。这要求你具备把知识点串成链路的能力,而不仅仅是孤立记忆。

所以我的建议是:复习时不要一条一条背题,要按“一条SQL从客户端到服务器再到存储引擎,完整走一遍”的视角来组织知识。接下来几章,我就是按这个思路展开的。

2. 索引与存储引擎:B+树不是背出来的

2.1 面试第一问:InnoDB和MyISAM的区别

这几乎是MySQL面试的必开场题。最稳妥的答法是先说底层存储结构,再说能力差异。

InnoDB和MyISAM都是索引与数据组织的不同方案。MyISAM的索引文件和数据文件是分离的,索引叶子节点存的是数据行的磁盘地址,属于非聚集索引组织方式。InnoDB的主键索引叶子节点直接存整行数据,属于聚集索引组织方式。这个结构差异直接决定了:InnoDB必须要有主键,而且主键查询效率极高;MyISAM的索引则可以独立于数据存在,做全文索引等场景更灵活。

能力层面的差异是:InnoDB支持事务、支持行级锁、支持外键,崩溃恢复能力强;MyISAM不支持事务、锁粒度是表级、崩溃恢复要靠repair table。所以网上说“MyISAM读快、InnoDB写快”,这个说法其实有误导性。MyISAM读快是快在非聚集索引的叶子节点不存数据、单条扫描更轻,但一旦有并发写,表锁会串行化,整体吞吐并不高。InnoDB的MVCC+行锁设计,在并发写场景下反而优势明显。

面试中你会遇到追问:“既然InnoDB这么好,为什么MySQL还保留MyISAM?”这个问题考察的是你是否了解历史背景。在MySQL 5.5之前,MyISAM是默认引擎,那个年代磁盘贵、数据量小、读写并发不激烈,MyISAM够用。后来InnoDB由Innobase公司开发并逐步成熟,被Oracle收购后成为MySQL默认引擎。今天你新建表还用MyISAM,反而会被质疑为什么不用更稳的方案。除非你的场景是“数据仓库层、只读归档表、允许表锁”,否则别给自己挖坑。

2.2 为什么偏偏是B+树

这个问题的完整答法是分三步:先排除其他数据结构,再解释B+树自身优势,最后落到InnoDB的存储特性上。

先用排除法。哈希索引可以做到O(1)等值查询,但做不了范围查询,InnoDB的普通索引要支持“大于、小于、BETWEEN”,哈希直接出局。二叉树在最坏情况下退化成链表,树深度不可控。红黑树是平衡二叉树,深度控制在O(logN),但数据量大了之后深度依然偏大——一千万行数据,红黑树深度大概在20多,意味着一次查询要访问20多个节点,放到磁盘IO上就是20多次随机读,不可接受。B树解决了“矮胖”问题,所有节点的数据都出现在整棵树里,每个节点能放更多索引项,高度大幅降低,通常3-4层就能撑起千万级数据。

那为什么是B+树而不是B树?这里必须说两个关键差异。第一,B+树只有在叶子节点才存数据行地址或整行数据,非叶子节点只存索引键值,所以同样的节点大小(默认16KB),B+树能塞进更多索引项,树变得更矮。第二,B+树的叶子节点用双向链表串起来了,天然支持范围扫描和顺序遍历,B树要做范围查询就得中序遍历,效率差一个量级。

我最近还看到有人问“InnoDB为什么默认16KB页大小”。这其实是因为机械磁盘的扇区是512B、4K对齐,16KB页能在一次IO读进足够多的索引项,同时避免页大小过大导致随机IO放大。一些云数据库会把页大小调整到32KB以适配特定业务,但通用场景下16KB就是硬盘盘的性价比选择。

2.3 聚集索引、回表与覆盖索引

这是索引章节的重头戏。你需要清晰说出三个概念。

聚集索引(clustered index)就是InnoDB主键索引,叶子节点存整行完整数据。一张表只能有一个聚集索引,因为数据行只能按一种物理顺序存放。非聚集索引(secondary index,也叫二级索引、普通索引)叶子节点存的是主键值,而不是数据行地址。你用二级索引查到数据后,还需要拿着主键到聚集索引里再查一次数据行,这个动作就是回表(table lookup)。

回表很容易成为性能瓶颈,所以面试官会问“怎么避免回表”。两个方案:覆盖索引和索引下推。覆盖索引就是你建立的联合索引包含了查询所需的所有列,这样二级索引的叶子节点上的主键值+联合索引字段已经能满足查询需求,不需要再回表。比如你有联合索引(user_id, status),查询SELECT status FROM user_order WHERE user_id = 123 AND status = 1,Extra列显示Using index,就是覆盖索引生效。

索引下推(Index Condition Pushdown,ICP)则是MySQL 5.6引入的优化。没有ICP时,联合索引的第一个字段匹配后,引擎会把所有命中的索引项都回表,再在Server层做其他条件下的过滤;有ICP后,索引里能判断的条件直接下推到存储引擎层过滤,减少回表次数。我见过不少候选人知道ICP这个名词,但说不清它的触发条件,这里提醒一句:ICP主要在二级索引上生效,对主键索引没有意义,因为主键索引叶子节点已经包含全部字段了。

2.4 最左前缀原则:不要死记,要理解排序

面试官问“联合索引(a,b,c)有哪些有效查询”,考察的就是最左前缀原则。我的建议是别背“从最左边开始连续匹配”这种话术,试着从索引构建的物理结构去理解。

联合索引在B+树里的排序规则是:先按第一个字段排序,第一个字段相同再按第二个字段排序,以此类推。所以它本质是一棵“字典序”排序树。你查询WHERE b = 1 AND c = 2,在整棵树上第一个字段是不确定的,无法利用索引的全局有序性去二分定位,所以只能全表扫描或者走其他索引。而WHERE a = 1 AND b= 2,则能先通过a定位到一个区间,再在这个区间内按b继续二分。

有两个容易被问翻的点。一是“WHERE b = 1 AND a = 2”能不能走索引?能。因为MySQL查询优化器会做条件重排,把a的条件放到前面,最终等价于“a = 2 AND b = 1”,所以最左前缀说的“最左”是指访问路径上的最左,不是SQL语句里写的最左。二是范围查询的截断问题。联合索引(a,b,c)上执行WHERE a > 1 AND b = 2,b的条件没法走索引,因为a的范围查出来后,b在区间内的有序性已经无法保证。这个考点几乎年年出现,记得区分“等值匹配”和“范围匹配”。

3. 事务隔离与MVCC:从脏读、幻读说起

3.1 四种隔离级别的本质区别

事务的四个隔离级别是MySQL面试的必背项,但很多人的理解停留在表格式背诵。我面试时喜欢追问一句:“为什么READ COMMITTED不会脏读,但REPEATABLE READ能杜绝?READ COMMITTED和REPEATABLE READ在实现上的核心差异是什么?”

正确答案是MVCC的ReadView生成时机不同。READ COMMITTED:每次快照读都会生成新的ReadView,所以它只能看到已经提交的事务,但同一条记录在同一个事务里被多次读取,结果可能不同,这就是不可重复读。REPEATABLE READ:只在事务的第一个快照读时生成ReadView,之后整个事务都复用这个ReadView,所以同一个事务里反复读同一条记录,结果都一样。

更底层的实现是undo log版本链。InnoDB的每一行记录都有隐藏字段:DB_ROLL_PTR指向该行的上一个版本,配合undo log形成版本链。快照读时,InnoDB通过ReadView判断版本链中哪个版本对当前事务可见:版本的事务ID小于min_trx_id的可见,大于等于max_trx_id的不可见,在中间区间还要看事务ID是否在活跃事务列表里。这个过程描述起来有点绕,但面试官听到你能说出“ReadView + 版本链 + 活跃事务列表”这三个关键词,基本就放心了。

3.2 幻读到底解决没解决

幻读是指在同一个事务里执行同一条范围查询,两次返回的行数不一样。比如第一次SELECT count(*)返回10行,第二次返回11行,多出来的那行就是幻行。

MySQL在REPEATABLE READ级别下,对幻读的处理要分两种读类型说清楚。

快照读(普通SELECT)下,MVCC的ReadView已经保证了事务内看到一致的快照,所以快照读不会产生幻读。但当前读(SELECT ... FOR UPDATE、UPDATE、DELETE)就不一样了。当前读必须读最新已提交版本,所以两个事务并发插入时,当前读可能看到新插入的行。

解决当前读幻读的方案是间隙锁(Gap Lock)和next-key lock。间隙锁锁的是索引记录之间的区间,比如一个查询条件落在(10, 20)区间,间隙锁会把10和20之间的插入动作全部挡住。next-key lock则是行锁和间隙锁的组合,既有行锁又有区间锁。所以REPEATABLE READ下,当前读的幻读其实是被next-key lock干掉的,但如果你没有走索引(退化成表锁),或者锁定的区间和并发插入区间不重叠,依然可能出问题。因此严谨的说法是:InnoDB在REPEATABLE READ下,通过MVCC和next-key lock基本解决了幻读,但严格隔离级别下仍有边界场景需要留意。

3.3 一个说服力很强的面试答案模板

被问到“你们数据库隔离级别是什么,为什么选它”时,别只回答“我们用的RR”。更加分的方式是带上下文和业务思考。你可以说:交易类系统核心表用的是REPEATABLE READ,因为InnoDB在RR下已经有next-key lock,对订单、账户这类需要一致性读和防幻读的业务更稳;但报表、日志类表会改成READ COMMITTED,因为逻辑简单、快照读代价更小,也避免RR下的间隙锁扩大锁范围导致并发插入被阻塞。

这个答案的好处是把隔离级别从“背概念”变成了“结合场景做取舍”,面试官立刻能看出你处理过真实问题。

4. 锁与日志:理解一致性的另一半拼图

4.1 行锁、表锁、意向锁怎么配合

很多面试者能说出“行锁粒度小、表锁粒度大”,但被问到“一个事务给某行加了行锁,另一个事务想加表锁,怎么快速判断能不能加”时就懵了。这就是意向锁(Intention Lock)存在的意义。

意向锁是表级锁,分为意向共享锁(IS)和意向排他锁(IX)。事务要给某行加共享锁时,先在表上加意向共享锁;要给某行加排他锁时,先加意向排他锁。这样其他事务想给整张表加表锁时,只要看表上有没有意向锁,就能快速判断是否存在行级冲突,不用去逐行扫描。意向锁之间互相兼容,只有真正的表共享锁和表排他锁会互相阻塞。

这里有个常见误区:InnoDB的行锁不是“锁在索引记录”上,而是锁在索引记录对应的索引条目上。如果UPDATE的WHERE条件没有走索引,行锁会退化为表锁。这个知识点几乎必考,因为它直接和线上死锁、锁等待挂钩。生产环境里不少“莫名锁表”的故障,根源就是一条没走索引的UPDATE把整表锁住了。

4.2 间隙锁与死锁的排查思路

死锁是生产环境最常见的MySQL事故类型之一。典型的死锁场景是两条SQL交叉加锁。比如事务A先锁了id=1的行,事务B先锁了id=2的行,然后A想锁id=2、B想锁id=1,两边互相等待,就形成死锁。

InnoDB检测到死锁后会自动回滚代价更小的事务,并抛出Deadlock found when trying to get lock; try restarting transaction错误。面试官问你“遇到死锁怎么办”,你光说“重试”是不够的,要说出排查链路。实际排查时,我一般按三步走:

  1. 登录数据库执行SHOW ENGINE INNODB STATUS,查看LATEST DETECTED DEADLOCK段,里面有死锁事务的SQL语句和持锁等待信息。
  2. 分析死锁的两个事务分别持有哪个索引的锁、想获取哪个索引的锁,定位是行锁冲突还是间隙锁冲突。
  3. 修正业务:调整SQL执行顺序,让所有事务都按同一顺序访问表;尽量走索引减少锁范围;对大事务做拆分。

另外,如果线上偶发死锁但SHOW ENGINE INNODB STATUS刷得快看不到,可以用performance_schema下的data_locks、data_lock_waits表去观测实时锁状态。这条经验是生产环境排查的加分项,面试提到会很亮眼。

4.3 redo log、undo log、binlog的分工

日志体系是理解MySQL“数据一致性”的核心,也是大厂面试的高频深水区。很多人在这一块面试时会挂,因为很少有人能把三份日志的分工和协作讲明白。

redo log是InnoDB存储引擎层的日志,记录的是物理修改“某个页的某个偏移量改成了什么值”。它采用WAL(Write-Ahead Logging)机制:事务提交时先把redo log刷到磁盘(innodb_flush_log_at_trx_commit参数控制刷盘策略),而数据页可以稍后再刷。这样即使数据库崩溃,也可以通过redo log重放恢复已提交事务的修改。这就是Durability(持久性)的底层保证。

binlog是MySQL Server层的日志,记录的是逻辑操作“某个表执行了UPDATE,影响了几行”。它主要用于主从复制和时间点恢复。redo log是循环写、会被覆盖;binlog是追加写、不会覆盖。两者缺一不可。

两阶段提交是保证redo log和binlog一致性的关键。事务提交过程分两步:先写redo log并标记为prepare状态,然后写binlog,最后把redo log标记为commit状态。为什么需要两阶段?因为如果先写binlog、再写redo log,崩溃恢复时可能binlog有记录但redo log没记录,导致从库执行了主库没提交的事务;反过来,先写redo log再写binlog,可能主库提交了但从库没有记录。两阶段提交就是为了让两份日志在崩溃恢复时能对齐。

undo log则服务于两个场景:事务回滚和MVCC版本链。每行数据的旧版本会通过DB_ROLL_PTR串联,事务回滚时可以通过undo log反向执行补偿操作。崩溃恢复时,如果redo log里出现了prepare状态的未完成事务,InnoDB会用binlog和undo log配合判断:binlog写成功则事务视为已提交,否则回滚。

我建议你在面试时用一个具体例子把这些串起来:“用户在余额表执行了UPDATE余额=余额-100,这条语句会先写undo log记录旧值,然后修改内存中的缓存页,写redo log标记prepare,再写binlog,再标记redo log commit,最后返回客户端成功。如果写完binlog但没标记commit时数据库崩溃,恢复时会发现redo log是prepare状态,且binlog已存在,判断事务有效,完成提交。”能把这个链路讲清楚,面试官基本不会再追问日志问题。

5. 主从复制与高可用:从原理到追延迟

5.1 复制原理:三个线程各司其职

主从复制背的是“三个线程”:主库的Binlog Dump Thread、从库的IO Thread和SQL Thread。

整体链路是:主库的Binlog Dump Thread把binlog事件发送给从库;从库的IO Thread负责接收并写入本地的relay log(中继日志);从库的SQL Thread读取relay log并重放到从库数据上。默认情况下复制是异步的:主库事务提交后不等待从库确认,所以主从间天然存在延迟窗口。

面试官如果追问“MySQL 5.7以后复制方式变了什么”,你要能说出半同步复制和GTID复制。半同步复制(semi-sync)指主库提交后至少要等待一个从库ACK才返回客户端成功,把延迟窗口缩小到从库网络往返时间。MySQL 5.7开始支持增强半同步,从库收到binlog并写入relay log后立即ACK,不等待SQL线程回放完成,性能更好。GTID(Global Transaction Identifier)则给每个事务分配一个全局唯一ID,从库通过GTID来定位复制位点,避免了传统基于文件名+偏移量的位点管理在切换主从时的复杂操作。

5.2 主从延迟:面试必问的生产难题

只要聊到主从复制,面试官一定会问“主从延迟怎么解决”。你要先理解延迟的表象本质:主库写入吞吐高时,从库的SQL线程是单线程重放,跟不上主库的写入速度,这就是最常见的延迟原因。MySQL 5.6之前的单线程复制在写压力大时会明显积压;5.7之后引入了多线程复制(MTS),可以按数据库、按表并行回放,但并行度依然受限于表级别的冲突。

结合生产经验,我平时排查主从延迟的思路是:

  • 先看SHOW SLAVE STATUS里的Seconds_Behind_Master和Relay_Log_Space。延迟大时中继日志会积压,Relay_Log_Space持续增长。
  • 判断是否只有一个大事务(比如DELETE大量旧数据)拖慢了SQL线程。这种情况即使开并行复制也没用,得从业务上拆批。
  • 如果长期延迟是常态,考虑升级到多线程复制,或者优化主库写入模型,减少大事务和热点行更新。

然后面试官会问“读写分离下怎么保证不读到旧数据”。几个常用方案:刚写完强制走主库(或者走主库读一段时间),这是“写后读一致”的经典做法;对一致性要求高的查询直接路由主库;利用缓存写入后失效、下次查询重建。这些方案本质上都在做“过期读”的规避,没有银弹,但能通过分层设计把不一致窗口压到业务可接受范围。

“怎么把远程库的某张表同步到本地”这种问题本质也在考这部分。我在实际项目里常用的手段是:数据量大且有增量更新需求时搭建主从,把远程库作为主库、本地作为从库,通过binlog同步。临时一次性同步,用mysqldump导出特定表再导入本地。注意mysqldump默认会锁表,线上执行要加--single-transaction避免长时间锁住业务表。这些细节说出口,面试官会默认你真的碰过数据同步。

6. 慢SQL与explain:把优化聊出实战感

6.1 explain关键字段:别只背 type 的含义

SQL优化是社招面试的高频模块,但很多人的回答停留在“加索引”。我建议你把explain的输出讲透,这才是高频加分的点。关键字段有这么几个:

  • type:访问类型。安从左到右由好到差排列为system > const > eq_ref > ref > range > index > ALL。至少要能说出const(主键或唯一索引等值查询)、ref(普通二级索引等值查询)、range(索引范围扫描)、ALL(全表扫描)。如果type显示ALL,基本说明索引没建好或没走对。
  • key:实际使用的索引名。很多人只关心是否用了索引,却容易忽略key_len,但key_len能算出联合索引实际用了几个字段。
  • rows:估算扫描的行数。注意这是估算值,不是精确值,但能反映优化器对代价的预判。
  • Extra:最容易忽略也最容易出答案的字段。出现Using index表示覆盖索引,Using index condition表示索引下推,Using where表示在Server层做了条件过滤,Using temporary表示用了临时表,Using filesort表示做了文件排序,后两者通常意味着性能隐患。

我工作中定位慢SQL,基本流程是:打开慢查询日志(slow_query_log=ON,设置long_query_time=1或更小),捞出一批慢SQL,挨个explain。先看type是不是ALL,再看key_len是否吃满索引,最后看Extra有没有temporary/filesort。三步下来,90%的慢查询病因都能找到。

6.2 索引失效的高频场景

索引失效是面试的高频陷阱题,我也踩过不少坑。最有价值的总结如下:

  • 对索引列做函数操作,比如WHERE DATE(create_time) = '2024-01-01',MySQL无法对函数结果建立索引映射,索引直接失效。正确写法是范围条件create_time >= '2024-01-01 00:00:00' AND create_time < '2024-01-02 00:00:00'。
  • 隐式类型转换。索引列是字符串类型,你用数字去查,WHERE phone = 13800000000,MySQL会把字符串转换为数字来比较,走不了索引。这是开发里出现率最高的隐性问题。
  • 前导模糊查询LIKE '%abc',索引失效;但LIKE 'abc%'能走索引,因为B+树的有序性支持前缀匹配。
  • OR连接的多个条件,如果其中一个字段没有索引,整个查询可能走全表扫描。拆成两个查询用UNION,或者给缺失字段建索引。
  • NOT IN、!=、<>通常会变成全表扫描,因为B+树天生擅长有序范围匹配,不等值条件让优化器放弃索引。

6.3 分页深翻页优化案例

面试官再往前一步,会问“数据量大了怎么优化深分页”。经典场景是SELECT * FROM orders ORDER BY id LIMIT 100000, 20,这条SQL虽然用了主键索引,但MySQL要先扫描、排序、丢弃前100000行,再返回20行。这就是深分页问题。

比较普惠的优化方案有三个维度:

一是延迟关联。先通过覆盖索引拿主键ID,再用主键去关联需要的数据行:SELECT * FROM orders WHERE id IN (SELECT id FROM orders ORDER BY id LIMIT 100000, 20)。因为子查询里走的覆盖索引不需要回表,能显著减少随机IO。

二是游标分页(seek method)。记住上一页最后一条记录的主键或排序字段值,下一页查询用WHERE id > last_id ORDER BY id LIMIT 20。这样每次查询都能直接跳到目标位置,时间复杂度稳定,但要求排序字段是唯一的、单调的,且不支持页面跳转。

三是限制总页数,这也是很多后台系统的实际做法。产品上允许用户只看前200页,搜索引擎也只给到一定的深度,这不是技术妥协,而是产品理性。

这道题没有标准答案,面试官要的是你分析“为什么慢”和“有哪些方案”,如果你能顺带分析每种方案的适用场景,就已经超出大部分候选人了。

7. 写给别人也是写给自己:复习MySQL的正确姿势

最后分享一点个人经验。很多同学花大把时间背题,结果面试官换一个角度问就答不上来。我的建议是:不要按题目复习,按“一条SQL的一生”来复习。

你试着把下面这条链路复述一遍:客户端连上MySQL,经过连接池、鉴权、SQL解析、优化器生成执行计划,然后进入InnoDB。如果是SELECT,走MVCC快照读或当前读;如果是UPDATE,先加锁,再写undo log,再修改缓冲池中的数据页,写redo log(prepare),写binlog,再标记redo log commit。提交后主库返回客户端成功,binlog被dump线程发给从库,从库IO线程写入relay log,SQL线程回放,从库完成同样的变更。与此同时,如果TPS高、从库回放跟不上,主从延迟出现,读写分离下就要考虑写后读一致。

你发现没有,这条链路把存储引擎、索引、事务、锁、日志、主从复制、数据一致性全部串在了一起。面试官不管你从哪问起,你都能沿着这条链路慢慢展开。这比背二十个孤立问题要强得多。

我在实际辅导候选人的过程中,反复说一个观点:面试结果不是靠面试前三天冲刺出来的,而是靠平时写代码时多问几个“为什么”。为什么这条SQL慢?为什么这个表要这个主键?为什么这段逻辑要坚持读主库?这些问题积累起来,就是你面试时信手拈来的素材库。

MySQL这块内容确实多,多到让人容易焦虑,但它的知识结构其实相当凝练。索引解决查询效率,事务解决并发正确性,锁和日志是透明度的两个支柱,主从结构解决高可用和扩展性。你把这四根柱子立起来,大厂面试里的MySQL题目,基本都在你射程之内。

返回列表