2023年度小满秋招数据库岗第一批笔试刚结束,我把整套卷子和备考过程完整复盘了一遍。先说结论:这批笔试题不算变态,但非常考验平时是否真的写过SQL、跑过慢查询、看过执行计划,纯靠背八股文的同学,大概率在场景题和手写SQL环节露馅。这篇文章把考点分布、答题思路、踩坑经验全部整理出来,给后面几批备考的同学做个参考,也聊聊我自己的体会。
需要说明的是,笔试内容覆盖范围比想象中广,从最基础的增删改查,到索引优化、事务隔离、数据库设计,再到主从同步、国产数据库适配都有涉及。如果你正准备数据库岗的校招笔试,这篇文章可以直接拿来当复习清单用。
1. 笔试的整体印象与考情梳理
1.1 这次笔试到底考察了什么
先说说卷面整体情况。整场笔试分为客观题、手写SQL题和场景设计题三大块,时间一共120分钟,题量大概是单选20道、多选10道、手写SQL 4道、场景设计2道。时间看起来够用,但实际做下来非常紧张,尤其是手写SQL部分,不仅要求写对,还要求考虑边界条件和执行效率。
从知识点分布来看,考察重点集中在四个方面:
- SQL基础与高级查询,包括多表联查、聚合函数、窗口函数、子查询优化
- 索引原理与SQL优化,包括B+树结构、覆盖索引、最左前缀原则、索引失效场景
- 事务与锁机制,包括ACID特性、隔离级别、死锁成因与排查
- 数据库设计与运维,包括三范式、ER图设计、主从同步、备份恢复、连接池配置
有意思的是,这次笔试还考了一道国产数据库相关的题目,问的是"从Oracle迁移到达梦数据库时,哪些语法和功能需要适配"。这说明现在企业招数据库岗,已经不满足于只会MySQL了,具备多数据库迁移和国产化适配意识的人会更受欢迎。
1.2 为什么企业要这么考
很多同学觉得笔试里的SQL题"随便写写能跑就行",这是典型的误区。企业笔试之所以设计成现在这个结构,背后是有明确逻辑的。
客观题部分主要筛掉基础不牢的人。数据库字段类型选错、隔离级别搞混、索引结构说不清,这些硬伤在笔试阶段不筛掉,入职后写出来的SQL就是生产事故的隐患。手写SQL题考察的是真实编码能力,通过你写的SQL语句能看出你是不是真的理解表结构、理解数据关系、理解索引使用。场景设计题则是模拟真实工作中"给你一个需求,你要设计出一套合理的表结构"的能力。
所以备考数据库岗笔试,不能只背知识点,必须动手写、动手设计。日常多写SQL、多调优慢查询、多复盘表结构设计,笔试的时候自然就有手感。
2. 必考核心知识点与答题思路
2.1 SQL基础:从增删改查到窗口函数
SQL基础部分虽然叫"基础",但笔试的考察方式并不基础。直接考"select 字段 from 表 where 条件"的题目很少,更多的是把多个知识点揉在一起,让你写出一条能够应对复杂业务场景的查询语句。
这次笔试题里有一道非常典型的题目:查询每个部门薪资排名前三的员工。很多同学第一反应是用group by加limit,但仔细想想就会发现,group by后取limit只能取到每个分组的一条记录或者聚合结果,要取前三名非常别扭。更合理的做法是用窗口函数:
SELECT department_name, employee_name, salary FROM ( SELECT d.department_name, e.employee_name, e.salary, DENSE_RANK() OVER (PARTITION BY d.department_id ORDER BY e.salary DESC) AS rn FROM employee e JOIN department d ON e.department_id = d.department_id ) t WHERE rn <= 3;这里我用的是DENSE_RANK而不是ROW_NUMBER,因为如果存在薪资相同的员工,ROW_NUMBER会随机分配一个排名,而DENSE_RANK会把相同薪资的人排在同一个名次,更符合业务语义。这个细节是我实际工作中踩过坑才记住的。
除了窗口函数,增删改查里的"涨姿势"点还有一个:批量更新数据时要注意where条件的写法。
UPDATE account SET balance = balance - 100 WHERE id IN (SELECT id FROM frozen_account WHERE status = 1);笔试时容易忽略的是,MySQL中直接对同一张表进行子查询更新会报错"You can't specify target table for update in FROM clause"。正确的做法是先包一层临时表,或者使用连表更新。这类题目考察的不是你知不知道update语法,而是你有没有在实际开发中处理过类似问题。
2.2 索引原理:B+树与索引失效场景
索引几乎是数据库岗笔试的必考内容,而且考得很细。如果你想拿高分,光知道"索引能加速查询"是不够的,必须理解索引的底层数据结构。
B+树是关系型数据库最常用的索引结构,它相比于B树的好处在于:所有数据都存储在叶子节点,并且叶子节点之间有指针相连,这样范围查询的时候只需要沿着叶子节点的链表顺序扫描即可,不需要回溯到上层节点。这也是为什么你在建索引的时候,MySQL会默认选择B+树而不是其他数据结构。
笔试中关于索引的常见问题还有"哪些情况会导致索引失效"。我把常见的失效场景整理成了一个速查表:
| 场景 | 示例 | 失效原因 |
|---|---|---|
| 对索引列使用函数 | WHERE YEAR(create_time) = 2023 | 函数改变了列的原始值 |
| 隐式类型转换 | WHERE mobile = 13800138000 | 字符串列与数字比较时发生类型转换 |
| LIKE前置通配符 | WHERE name LIKE '%张' | 无法利用索引有序性 |
| OR连接非索引列 | WHERE age = 20 OR name = '张三' | 优化器可能选择全表扫描 |
| 联合索引不满足最左前缀 | 索引(a,b),条件只用了b | 联合索引按a先排序 |
关于联合索引,笔试还经常考"为什么最左前缀原则有效"。其实很简单:联合索引本质是先按第一个字段排序,第一个字段相同的再按第二个字段排序。如果你跳过第一个字段直接用第二个字段查询,索引的排序结构就没法用上了,就像一个只有姓名拼音索引的通讯录,你非要去查所有"住在朝阳区的人",索引根本帮不上忙。
2.3 事务、锁与并发控制
事务这块,ACID四个特性必须脱口而出,同时要理解每个特性对应数据库的哪种机制。原子性靠undo log实现,持久性靠redo log实现,隔离性靠锁和MVCC实现,一致性靠前三者共同保证。笔试如果考到"数据库宕机后为什么数据不会丢",答案就在redo log。
隔离级别也是高频考点。读未提交、读已提交、可重复读、串行化这四级的区别,关键看能否解决脏读、不可重复读、幻读这三个问题。MySQL默认的隔离级别是可重复读,但InnoDB引擎通过间隙锁在一定程度解决了幻读问题。我建议在复习的时候画一张表记住每个级别能防什么、不能防什么:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 |
| 读已提交 | 不会 | 可能 | 可能 |
| 可重复读 | 不会 | 不会 | 可能(InnoDB间隙锁可规避) |
| 串行化 | 不会 | 不会 | 不会 |
锁机制里,行锁和表锁的对比、悲观锁和乐观锁的适用场景、死锁的成因和排查,这些都要做到有问必答。死锁的典型例子是两个事务互相持有对方需要的资源,比如事务A先更新id=1再更新id=2,事务B先更新id=2再更新id=1,两者同时执行就会互相等待。实际排查死锁时,MySQL可以通过SHOW ENGINE INNODB STATUS查看最近一次死锁的详细信息,定位是哪两条SQL、持有哪些锁、等待哪些锁。
3. 数据库设计题到底该怎么答
3.1 范式与反范式:别被"三大范式"框死
数据库设计是笔试中区分度较大的题目,也是最贴近实际工作的一项考察。很多教材把三大范式讲得神乎其神,但实际工作中很少有人会为了满足第三范式把所有表拆成极细的颗粒度。笔试中考察范式,目的是看你能否在规范性和性能之间做出合理权衡。
第一范式要求字段不可再分,这是硬约束,基本所有表设计都要满足。第二范式要求非主键字段完全依赖于主键,第三范式要求非主键字段之间不能有传递依赖。通俗点理解:第二范式管的是"这张表的主键到底能不能唯一确定这一行",第三范式管的是"这张表里的字段是不是都只跟这张表的主键有关,而不是跟其他非主键字段有关"。
但笔试如果出"根据需求设计电商订单系统的表结构",你千万不要一上来就按范式把所有表拆得七零八落。订单表需要冗余一个用户昵称或者商品名称快照,即使这违反了第三范式。为什么?因为订单生成之后,商品改价、用户改名都不应该影响历史订单的展示。这个冗余字段就是反范式设计,它换取了查询性能和数据稳定性。能够在答卷里主动说明"这里我做了反范式冗余,因为XX原因",相当加分。
3.2 场景设计题:从ER图到建表语句
这次笔试的场景设计题是设计一个学生选课系统,需求包括:学生信息管理、课程信息管理、选课记录管理、成绩录入与查询。看似简单,但拿满分不容易,因为有几处隐含考点。
第一,选课记录表必须设计联合唯一约束,防止同一学生重复选同一门课。这个约束不仅是业务要求,也是面试官想看到的细节。
CREATE TABLE course_selection ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', student_id BIGINT NOT NULL COMMENT '学生ID', course_id BIGINT NOT NULL COMMENT '课程ID', score DECIMAL(5,2) DEFAULT NULL COMMENT '成绩', selected_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '选课时间', UNIQUE KEY uk_student_course (student_id, course_id), KEY idx_course_id (course_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='选课记录表';第二,成绩字段要使用DECIMAL而不是FLOAT或者DOUBLE,因为浮点数在比较和计算时存在精度问题。笔试如果考到这个知识点而你没写,说明你缺少实际开发经验。
第三,除了主键索引,我额外给course_id建了索引,因为业务上经常要查询"某门课程有哪些学生选了"。而联合唯一索引uk_student_course本身就覆盖了student_id前缀的查询场景,所以不需要单独为student_id再建索引。这种索引设计上的考量,是区分度最高的地方。
字段类型的选择也是设计题的隐藏考点。手机号建议用varchar存,不要用bigint,因为手机号可能包含前缀、国家码,而且不需要参与数值运算。状态字段用tinyint即可,不要一上来就设计int(11)。时间字段建议用datetime或timestamp,除非有跨时区需求,否则不需要设计成字符串。
4. 高可用与运维:主从同步、连接池与性能排查
4.1 主从同步原理与常见延迟问题
笔试中出现主从同步题目,通常不是让你手工搭建一套MySQL集群,而是考察你对同步原理的理解和排障思路。主从同步的核心是基于binlog的日志复制。主库把变更写入binlog,从库的IO线程把binlog拉取到本地并写入relay log,从库的SQL线程再重放relay log中的数据变更。
这里有个常见的坑:如果binlog格式设置不合理,会导致主从数据不一致。binlog有STATEMENT、ROW、MIXED三种格式。STATEMENT格式记录的是SQL语句本身,日志量小,但如果SQL使用了UUID()、NOW()这类不确定性函数,从库重放的结果可能与主库不一致。ROW格式记录的是每行数据的变化,一致性最好,也是目前生产环境推荐使用的格式,缺点是日志量偏大。MIXED格式是MySQL根据SQL类型自动选择,兼顾两者。
关于主从延迟,笔试常问"主从延迟产生的原因以及如何解决"。原因无非是:从库的SQL线程单线程重放速度跟不上主库的并发写入;从库硬件性能比主库差;大事务导致主库binlog在从库重放耗时过长;从库上有慢查询或锁等待阻塞了SQL线程。解决办法包括并行复制、升级从库硬件、拆分大事务、优化从库上的查询。
4.2 连接池参数与"审计引起索引争用"这类怪异问题
连接池是Java后端开发绕不开的工具,笔试中经常以配置题的方式考查。你需要理解为什么用连接池:因为数据库建立连接是一个开销很大的操作,频繁创建销毁连接会拖垮数据库和应用程序。连接池就是维护一批已经建立好的连接,应用需要时直接取,用完归还,避免重复握手认证的开销。
以HikariCP为例,核心参数有这么几个:
- minimumIdle:最小空闲连接数,建议和maximumPoolSize一致,避免频繁创建新连接
- maximumPoolSize:最大连接数,不是越大越好,还要考虑数据库能承受的连接数上限
- connectionTimeout:获取连接的超时时间,默认30秒,生产环境建议设置短一点,比如3秒
- maxLifetime:连接最大生命周期,要小于数据库的wait_timeout,避免被数据库服务端断开后池中还留着无效连接
这次笔试还出现了一道比较怪异的题目,问的是"数据库开启审计后引发索引争用,如何排查和解决"。实际上,数据库开启审计功能后,每一次操作都可能被记录到审计日志中,高并发场景下审计日志的写入会和业务SQL产生磁盘IO竞争,同时审计锁与索引的更新操作也会产生锁等待,导致SQL响应变慢。
解决思路通常有几种:调整审计策略,只记录权限变更、DDL等高风险操作,而不是记录所有DML;把审计日志存储到独立的磁盘或者独立的表空间,减少与业务数据文件的IO竞争;把审计写入从同步改成异步批量写入;如果对审计实时性要求不高,可以定期轮转审计日志,减小单文件带来的写入压力。这道题考的不是单纯的技术参数,而是你能不能从"系统整体视角"去分析问题。
4.3 数据备份恢复与容灾意识
数据库岗笔试中备份恢复的考点非常务实,考的就是你知不知道常见的备份工具和恢复流程。逻辑备份用mysqldump,适合数据量较小的场景,导出的是SQL语句;物理备份用XtraBackup,直接复制数据文件,适合大数据量下的快速备份。笔试中如果让你设计备份策略,正确方向是全量备份加增量备份结合。比如每天凌晨2点做一次全量备份,每2小时做一次binlog增量备份,这样即使数据库在下午4点崩溃,也能用全量备份加上当天的binlog恢复到4点的状态。
关于恢复流程,需要特别强调"先恢复全量备份,再应用binlog增量"。很多同学答成"直接把最新的数据文件拷贝回去",这不算错,但忽略了binlog的应用,会丢掉全量备份时间点到故障时间点之间的数据变更。数据一致性校验也很重要,恢复完成后要对比关键表的行数、checksum,确保数据完整。
5. 国产数据库与生态工具
5.1 从Oracle到国产数据库:迁移适配怎么做
这几年国产数据库的讨论热度越来越高,从达梦、人大金仓到GaussDB、Doris,笔试题也逐渐开始涉及。今年小满秋招笔试中出现了一道关于Oracle迁移到达梦数据库的适配题目,虽然分值不高,但能答出来的同学不多,因为这个知识点在很多人的复习范围之外。
达梦数据库(DM8)是国内最常见的Oracle兼容型数据库之一,很多政府、金融项目都在用。从Oracle迁移过来,主要适配点包括:数据类型映射(如NUMBER对应DECIMAL、VARCHAR2对应VARCHAR)、存储过程语法差异、序列和触发器逻辑、自带函数库的差异。其中最容易踩坑的是分页查询,Oracle用的是ROWNUM,达梦则直接支持LIMIT语法。
这类题目的意义在于,企业数据库岗的日常工作不再只跟MySQL打交道,具备迁移和适配能力的人会非常抢手。笔试中如果你能主动写出"迁移前先做兼容性评估,迁移后要做数据一致性校验和应用回归测试",就已经比绝大多数考生高出一个level。
5.2 数据库工具链:提升效率的利器
笔试中偶尔会出现工具类的选择题,比如"下面哪个工具可以导入导出数据库脚本""如何通过IDEA连接数据库并导出数据"。这类题目不难,但如果你平时只用一个Navicat,可能就会卡住。
我常用的工具组合是这样的:写SQL和调试用IDEA自带的Database面板或者DataGrip,数据量小、操作简单的场景用Navicat,PostgreSQL和各类开源数据库统一用DBeaver,因为它是免费开源的。导出数据库脚本时,IDEA的Database面板可以右键选中表或Schema,选择"Export Data"或者"Generate Script"导出建表语句和数据,非常方便。
另外,如果你要在已有重复数据的表中添加唯一约束,MySQL会直接报错"Duplicate entry"。实战中的处理方法是先查出重复数据并清理,再添加唯一索引。笔试如果出现这个场景,能提前写出排查重复数据的SQL,比如:
SELECT user_id, COUNT(*) FROM user_account GROUP BY user_id HAVING COUNT(*) > 1;这代表你真的处理过脏数据问题,而不是单纯背过"唯一约束"的概念。
5.3 说说向量数据库与新型数据库
现在不只是关系型数据库的天下,向量数据库、时序数据库也在很多实际项目中落地了。笔试偶尔会出现这类名词解释题,比如"什么是向量数据库,它和传统关系型数据库的区别是什么"。
向量数据库专门用来存储和检索高维向量,典型应用是推荐系统、图像检索以及大模型的知识库。ChatGPT带火了一波向量数据库热潮,Milvus、Chroma、Pinecone这些产品也被频繁提及。向量数据库与传统数据库的本质区别在于:它存的是通过模型生成的embedding向量,查询的时候用的是最近邻检索(如余弦相似度),而不是等值比较或范围查询。如果你后续看到"向量数据库"相关岗位的需求,至少要知道它和大模型应用之间的关系。
时序数据库则主要面向监控数据、IoT传感器数据这种高写入、时间序排列的数据场景,最典型的开源产品是InfluxDB和TDengine,Doris等分析型MPP数据库也常被用来做海量数据分析。笔试如果考到,能从数据模型、写入模式、查询模式三个角度对比,基本就能拿分。
6. 失分点复盘与备考建议
6.1 笔试中最容易丢分的地方
复盘这次笔试,我整理了五个典型的失分点,希望能帮助你在下一次笔试中提前规避。
第一,SQL手写题忽略边界条件。比如"查询每个部门薪资最高的员工",很多人只写了group by max,完全没考虑如果有多个员工薪资相同怎么处理。一个简单的窗口函数就能解决,但平时不练就会想不到。
第二,索引失效场景答不完整。背过"LIKE前置通配符会失效"的人很多,但能把"隐式类型转换""对索引列使用函数"都答全的人很少。面试官问"还有吗"的时候,你如果说不出第五个场景,说明知识还是零散的,没有形成体系。
第三,事务隔离级别和锁机制混淆。可重复读和读已提交到底差在哪,间隙锁是干嘛用的,这些一定要从原理上理解,不能只背结论。我见过很多同学把"不可重复读"和"幻读"混为一谈,把"间隙锁"说成"表锁",这种错误一旦犯就是整道题零分。
第四,场景设计题字段类型乱用。成绩用FLOAT、手机号用INT、状态字段用VARCHAR,这些都是设计题中的雷区。笔试阅卷人看到这种答案,基本可以断定你没有真实项目经验。
第五,完全不知道国产数据库和新趋势。很多同学复习时只看MySQL和Oracle,对达梦、人大金仓、openGauss、Doris这些名词一窍不通。现在校招笔试题越来越贴近企业真实技术栈,这个盲区一定要补上。
6.2 高效的备考路线与长期积累
基于这次笔试的复盘,我总结了一套数据库岗的备考路线,核心思路是"理论+实战"双线并行。理论方面,建议把《高性能MySQL》和《数据库系统概念》作为主参考书,前者偏实践、后者偏原理,两本配合着看。实战方面,建议自己在本地安装MySQL 8.0,准备一套样例数据,每天练习10道SQL题,重点练习窗口函数、多表联查、分组聚合这些高频考点。
遇到不清楚的问题一定要动手验证。比如你怀疑某个SQL写法会触发索引失效,直接在表里造十万条数据,用EXPLAIN看执行计划,一下就明白了。纸上谈兵永远记不住,只有自己跑过一遍的执行计划才能真正成为你的肌肉记忆。
另外,平时可以多关注一些数据库技术社区和开源项目,了解行业动态。数据库领域不像前端那样日新月异,但每年都会有新工具、新特性出来。向量数据库、国产数据库适配、数据库自动运维这些方向,正在成为新的面试考点。保持信息渠道畅通,笔试的时候遇到陌生概念也不至于完全懵。
我个人在复盘这次笔试时还有一个小技巧想分享:每道错题不要只记录正确答案,而是把错误原因和背后的原理一起写下来。比如"联合索引失效"这道题,旁边备注"联合索引(a,b),查询只用b时,相当于从通讯录的姓氏索引去查名字,自然失效"。用这种通俗类比帮助理解,复习效率会高出很多。
笔试只是第一关,后面还有技术面、HR面,但把笔试准备扎实了,很多面试题其实也顺势准备了。希望这份复盘对你接下来的秋招笔试有帮助。