我印象里浩鲸科技2020届数据库岗的笔试A卷应该是不少校招生回忆里比较有分量的一份题。浩鲸科技的前身是中兴软创主要做电信运营商、政企数字化这条线的业务所以它家的数据库笔试不像互联网大厂那样追求偏题怪题反而非常务实重点全落在关系型数据库的基本功、SQL硬功夫和设计思路上。这份卷子放在今天回头看依然是很好的数据库基础能力自测题尤其适合正在准备校招、或者刚入行想系统补一遍数据库知识的人。我当时拿到这份卷子的时候第一反应是题量不小选择题、填空题、SQL题、数据库设计题都有整体难度阶梯拉得比较开。前面概念题只要认真背过书基本都能拿分但后面的SQL题和设计题是真能拉开差距的地方。这篇文章我就按这份A卷的考察脉络把核心考点、答题思路、实操方法以及我在实际工作中踩过的坑都拆开讲一遍希望能帮你把这类数据库笔试彻底吃透。1. 整体设计与思路拆解这份卷子到底在考什么1.1 从浩鲸的业务背景反推考察目标想要答好一份笔试不能只盯着题目本身得先理解出题人想要什么样的人。浩鲸科技的核心业务是电信运营商BSS/OSS系统、智慧城市、政企数字化这类系统的共同特点是什么数据量大、并发高、业务逻辑复杂、可用性要求极高。电信计费系统如果挂了影响的可能是几百万用户的账单和充值这个容错率是非常低的。所以浩鲸的数据库岗位笔试本质上是在筛选具备三方面能力的人第一理论基础扎实清楚事务、索引、锁、范式这些核心概念背后的原理而不只是会背名词解释第二SQL实战能力强能写复杂查询、能优化慢SQL因为这类系统里最多的就是各种统计报表和批量数据处理第三有数据建模意识面对多表关联的业务场景能设计出结构清晰、扩展性好的库表。这三点对应的正是试卷里概念题、SQL题、设计题三大板块。对比一下互联网大厂的数据库笔试你会发现大厂更爱考分布式数据库、中间件、分库分表这些偏架构的东西而浩鲸这类政企数字化厂商更看重你对成熟关系型数据库的驾驭能力。说白了它们要的是能快速上手干活的人不是需要从头培养的架构师。这也是为什么卷子里Oracle和MySQL的内容都会涉及电信行业老系统用Oracle的非常多新项目又普遍转向MySQL两边都得懂。1.2 题型组合背后的出题逻辑这份A卷的题型分布其实是经过设计的。选择题和填空题承担的是“海选”功能覆盖面广、分值不高但能快速筛掉基础不牢的人。比如事务的ACID特性、SQL语句的执行顺序、索引失效的典型场景、char和varchar的区别这些都属于“背了就会不背就懵”的题目没什么技巧含量纯看复习有没有到位。SQL题和设计题承担的是“决赛”功能分值占比高而且通常没有唯一标准答案。阅卷人看的是你的解题思路、SQL写的规不规范、表结构设计有没有考虑到数据冗余和查询效率。我当年交卷的时候旁边有个同学提前半小时就交卷了后来聊起来才知道他选择题基本靠蒙SQL题只写了第一问。这种卷子交上去基本就是陪跑。所以准备这类笔试正确的策略应该是概念题花40%精力把高频考点背到滚瓜烂熟SQL题花40%精力把窗口函数、group by、多表关联这些基本功练到条件反射设计题花20%精力理解清楚ER模型和范式能画出清晰的表结构关系。这个投入产出比是最划算的。2. 核心考点拆解那些必考且容易丢分的知识点2.1 事务ACID从背诵到能讲清楚ACID四个特性几乎必然出现在数据库笔试里浩鲸这份卷子也不例外。但选择题考的是“哪个是事务的特性”这种送分题后面简答题往往还会让你结合场景说明某个特性。很多人栽在答不全、或者只答了名词没答出本质。原子性指的是事务中的所有操作要么全部成功要么全部回滚不存在中间状态。我用转账举例A账户扣100元和B账户加100元必须同时发生或同时不发生如果只扣了A没加B这钱就凭空消失了。一致性指的是事务执行前后数据库的完整性约束不能被破坏比如账户余额不能为负数。隔离性指的是多个事务并发执行时一个事务不应该看到其他事务未提交的数据就像四个人在四个隔间里改同一份档案互相不能干扰。持久性指的是事务一旦提交它对数据库的修改就是永久的即使系统崩溃也要能恢复这就是redo log存在的意义。很多人在复习时会忽略隔离性和一致性的区别这里我多说一句隔离性是手段一致性是目的。数据库通过锁和MVCC实现隔离性最终是为了保证并发场景下数据仍然是一致的。笔试如果出简答题你把这条逻辑链讲清楚比单纯背四个名词要得分高得多。2.2 索引为什么是B树而不是二叉树或哈希表索引相关题目在A卷里占比不低选择题、SQL优化题都会涉及。最常考的一道题是为什么InnoDB的索引结构选B树不选二叉树、红黑树或者哈希表这道题看着简单但很多人答不到点子上。哈希表适合等值查询也就是where id 5这种时间复杂度是O(1)确实快。但数据库查询里大量场景是范围查询比如where age between 18 and 30哈希表就废了因为它只能算单个key的位置无法有序遍历。二叉树的问题是树的高度不可控数据量大时退化成链表查询次数激增。红黑树虽然是平衡树但每层节点最多两个子节点同样是1000万条数据树的高度明显高于B树。B树的优势有两点第一矮胖每个节点能存很多key1000万条数据大概只要3到4层查询时磁盘IO次数很少第二叶子节点通过链表串联天然支持范围查询和排序select * from table where id 100只需要从第一个满足条件的叶子节点开始往后遍历就行。用人话说B树把“查找”和“遍历”这两件数据库最常干的事都优化到位了所以它成了关系型数据库索引的事实标准。2.3 锁机制与隔离级别一道题串起整个并发体系锁和隔离级别是这张卷子里最容易失分的部分因为涉及的概念多且相互关联。我建议你复习时把它们放在一条线上理解事务并发会产生什么问题脏读、不可重复读、幻读数据库用什么机制解决锁和MVCC不同隔离级别下这些问题哪些被解决、哪些还存在。共享锁和排他锁是基础共享锁可以多个事务同时持有大家都能读排他锁只能一个事务持有别人既不能读也不能写。InnoDB默认的隔离级别是可重复读它通过MVCC多版本并发控制间隙锁解决了幻读问题。MVCC的思路是每行记录保存多个版本读操作读取的是快照写操作通过版本链和undo log实现回滚。笔试里常见的坑是有人问可重复读是不是完全解决了所有并发问题不是。可重复读只解决了快照读下的幻读如果事务里用了select ... for update这种当前读还是可能遇到幻读。这个细节我在后来的工作中也被坑过一次有个统计报表功能先查库存再扣减两个接口并发调用结果库存扣成负数了。后来排查发现就是用了可重复读隔离级别下的当前读间隙锁没有正确覆盖导致的。笔试可能只考概念但工作里这些细节都是真金白银的教训。2.4 范式与反范式理论要懂更要会用范式题在A卷里通常是给你一组字段让你判断达到了第几范式或者让你规范化成3NF。这种题有固定套路但很多人因为不熟悉范式的定义而丢分。第一范式要求字段不可再分比如“联系方式”这个字段里同时存了手机和邮箱就不满足1NF第二范式要求非主键字段完全依赖于主键不能只依赖主键的一部分典型场景是联合主键表里某个字段只跟其中一个主键相关第三范式要求非主键字段之间不能有传递依赖比如“员工表”里有“部门编号”又有“部门名称”部门名称其实是通过部门编号间接依赖员工编号的这就违反3NF。但我想提醒的是笔试考你范式不代表实际设计表就要死守3NF。反范式在真实项目里太常见了。我在浩鲸系的项目里见过不少统计报表表就是故意冗余字段把需要join三张表才能查出来的数据直接存在一张大宽表里查询快得飞起。范式是为了减少数据冗余和更新异常但冗余字段的代价无非就是多占点磁盘在查询性能面前完全可以接受。所以正确的姿势是笔试按标准范式答工作按实际场景灵活设计。3. 实操过程与核心环节实现SQL题和设计题的现场解法3.1 分组取Top N窗口函数是标准答案SQL题里必考一类题目按某个维度分组取每组前N条记录。比如“查询每个部门工资最高的前两名员工”。这种题在浩鲸这类公司的实际业务里非常常见报表系统里到处是这种需求。我建议你掌握三种写法笔试时优先用窗口函数。SELECT department_id, employee_name, salary FROM ( SELECT department_id, employee_name, salary, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn FROM employee ) t WHERE t.rn 2;窗口函数的思路很清晰PARTITION BY department_id把数据按部门分组ORDER BY salary DESC在组内按工资排序ROW_NUMBER()生成组内序号最后外层过滤出前两名。这种写法在MySQL 8.0、Oracle、SQL Server、PostgreSQL里都支持是标准解。如果你笔试时遇到的数据库版本比较老比如MySQL 5.7没有窗口函数那可以用关联子查询或者用户变量。关联子查询的思路是找“在该部门内工资比它高的人不超过1个”的员工也就是排名前二。写法如下SELECT department_id, employee_name, salary FROM employee e WHERE ( SELECT COUNT(DISTINCT salary) FROM employee e2 WHERE e2.department_id e.department_id AND e2.salary e.salary ) 2;这种写法的逻辑是工资比当前员工高的人数为0或1说明当前员工排前二。理解它有助于你加深对SQL执行逻辑的把握但实际开发里能用窗口函数尽量用性能好、可读性高。3.2 连续N天登录用户日期差值的经典套路另一类高频SQL题是“统计连续登录N天的用户”。我在浩鲸相关项目的用户行为分析里也写过类似的查询。核心套路是利用一个数学性质如果用户在第1天、第2天、第3天登录登录日期减去行号之后得到的是同一个基准日期这个基准日期相同的行为一组组内连续天数就是该组的行数。SELECT user_id, COUNT(*) AS continuous_days FROM ( SELECT user_id, login_date, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS group_date FROM login_log ) t GROUP BY user_id, group_date HAVING COUNT(*) 3;这里的思路可以类比成把不连续的日期“拉”回一条水平线连续日期减去递增的序号差值必然相同隔了一天再登录差值就多一天自然分成不同组。理解了这个数学原理遇到变体题比如“连续登录且每天消费超过100元”也就是在窗口函数里加个过滤条件的事底层套路不变。3.3 数据库设计题员工与部门的完整设计过程A卷的最后一道大题通常是设计题给你一个业务场景让你设计表结构。我以最经典的“员工-部门”场景演示完整流程。业务需求是每个部门有多个员工每个员工只属于一个部门需要记录员工的姓名、入职时间、工资、岗位部门有名称、所在地还可能要查每个部门的员工数和平均工资。第一步是识别实体和关系。实体是部门和员工关系是一对多。第二步是设计表结构。部门表的主键是部门编号字段包括部门名称、所在地。员工表的主键是员工编号外键是部门编号字段包括姓名、入职时间、工资、岗位。第三步是加索引。外键部门编号上一般要建索引因为按部门统计是高频查询工资字段如果是排序条件也可以考虑索引。CREATE TABLE department ( dept_id INT PRIMARY KEY, dept_name VARCHAR(50) NOT NULL, location VARCHAR(100) ); CREATE TABLE employee ( emp_id INT PRIMARY KEY, emp_name VARCHAR(50) NOT NULL, hire_date DATE NOT NULL, salary DECIMAL(10,2) NOT NULL, position VARCHAR(50), dept_id INT, CONSTRAINT fk_employee_dept FOREIGN KEY (dept_id) REFERENCES department(dept_id) );关键点有两个一是外键约束要不要加加了保证参照完整性批处理导数据时可能会拖慢速度考试场景加就好二是设计时要预留扩展性比如未来可能有员工调岗的需求那员工和部门就不该是固定的一对多而应该拆成中间表。回答设计题时把扩展性考虑说出来是很加分的。4. 常见问题与排查技巧实录笔试丢分点全部列给你4.1 概念题高频易混对照表复习这类校招数据库笔试时下面这些容易混淆的概念基本是必考且必错的我整理成了一张速查表。对比项核心区别笔试常见考法char vs varcharchar定长varchar变长char(10)存“abc”占10字节varchar(10)只占3字节delete vs truncatedelete逐行删可回滚truncate删表重建不可回滚问哪个操作能恢复where vs havingwhere在分组前过滤having在分组后过滤问“平均工资大于5000的部门”该用哪个count(*) vs count(字段)count(*)统计所有行count(字段)忽略NULL问NULL会不会被计数drop vs deletedrop删表结构delete删数据问误删表后能否恢复内连接 vs 左连接内连接只返回匹配行左连接返回左表所有行问某需求该用哪种连接死锁 vs 活锁死锁是互相等待永远阻塞活锁是不断让出永远拿不到锁问死锁必要条件我当年笔试时就栽在char和varchar这道题上当时想当然选了“varchar查询更快”后来才知道char在定长时反而因为不需要计算长度某些场景访问更快但更主要的区别是存储空间。这种题单位置就是送分题丢了很可惜。4.2 索引失效的六种真实场景SQL优化题里判断索引是否生效是必考技能。我总结了六种最容易踩的索引失效场景对索引列使用函数比如where YEAR(hire_date) 2020只要写了函数索引基本废了隐式类型转换比如varchar类型的字段跟数字比较like以通配符开头比如where name like %张%走不了索引使用or且or两边不是同一个索引联合索引不满足最左前缀原则索引列进行了运算比如where salary * 2 10000。这里我想特别说下“最左前缀原则”。联合索引(a,b,c)实际相当于建了(a)、(a,b)、(a,b,c)三个索引。查询时如果不带最左列a索引就用不上。这就像查字典先查拼音再查部首如果你上来只按部首查那就用不了拼音索引。理解了这一点很多看似奇怪的问题答案就清楚了。4.3 SQL书写顺序与执行顺序的差异笔试里常考一道“写出SQL各个子句的执行顺序”的题。很多人背了MySQL的语法顺序select、from、where、group by、having、order by、limit但执行顺序完全不是这样。真正的执行顺序是from先确定数据源where过滤行group by分组having过滤分组select投影列order by排序limit截断。这个顺序理解透了对调试SQL帮助非常大。比如你可能会遇到“where里明明有聚合函数count怎么报错”的问题原因就是聚合发生在group by阶段而where在group by之前执行那时候还没有分组概念。正确写法是用having过滤分组条件。4.4 笔试答题时间分配建议以浩鲸A卷为例总时长一般在90到120分钟。我建议选择题和填空题控制在25分钟以内这些题会就是会不会就蒙一个跳过去不要纠结。SQL题至少留35分钟因为要写完整的SQL语句、要考虑边界情况、要检查能不能跑通。设计题留20到30分钟先画清楚表结构和关系再写SQL不要上来就建表。剩下5到10分钟检查重点看有没有漏题、SQL关键字有没有拼错、建表语句有没有写反逗号。5. 从笔试到面试延伸准备与复习路径5.1 面试官会怎么追问笔试考的是广度面试考的是深度。如果你笔试里写了会窗口函数面试官很可能追问窗口函数和group by的区别是什么窗口函数不会减少行数它只是对每行附加一个聚合计算的结果而group by会合并多行。如果你写了会建索引面试官可能追问什么情况下建了索引反而更慢数据量很小的时候全表扫描比走索引更快因为索引查询需要额外的回表操作。结合浩鲸的业务面试官还可能问计费系统里每天产生千万级的流水记录怎么设计存储和查询方案这类开放型问题没有标准答案考察的是你的思路是否完整。我的建议是围绕“分库分表解决存储和写入瓶颈、汇总表解决查询瓶颈、归档策略控制数据总量”这三个方向来组织答案条理清晰比堆砌术语重要。5.2 结合业务场景理解数据库知识我特别想强调一点准备这类笔试时不要纯粹为了背题而背题要尝试把知识点映射到具体业务场景。比如学事务时就想想电信充值场景用户充了100元运营商余额系统加100、支付系统扣100任何一个失败都会出问题学索引时就想想要统计某个月的话单总量怎么建索引才能让报表跑得快学隔离级别时就想想要支持客服同时查用户账单和用户充值怎么避免两边数据不一致。这种“场景化理解”的好处是笔试遇到变体题你也能从容应对面聊的时候谈起业务来也不会显得像个只会背书的书呆子。浩鲸这类做政企项目的公司特别看重校招生能不能快速理解业务、能不能把技术和业务对接上。5.3 推荐复习路径结合我个人经验高性价比的复习路径分三步。第一步是系统过一遍理论找一本数据库教材或者一份系统性的笔记重点吃透事务、索引、锁、隔离级别、范式这几块不求多但求透。第二步是刷SQL题推荐在LeetCode数据库题库或者牛客网的SQL专项里刷够50题以上覆盖关联查询、聚合统计、窗口函数、子查询这些题型。第三步是拿一套历年的真题模拟考试限定时间、手写SQL感受一下真实考场节奏。我就是靠这个路径在后来转做数据库相关工作的时候依然觉得当年打下的基础很管用。现在带校招生的时候我也经常让他们先拿这份卷子自测一遍不是说要求他们考多高分而是通过做卷子暴露知识盲区。最后再分享一个小技巧除了这份记忆里的A卷考点平时多看下热门数据库话题里的年度高频问题比如国产数据库的适配迁移、达梦和人大金仓的运维、数据库同步工具的选择等这些趋势类信息在面试自由交流环节非常能体现你的行业敏感度。我当时就是聊到某一轮面试时主动提了一句传统Oracle往国产化数据库迁移的注意点面试官明显来兴趣了后面聊了足足二十分钟。数据库这个方向从来不是会写几条SQL就能立足的知识体系越宽路就越走越宽。