
考完小满春招数据库岗第二批笔试从考场出来那一小时我在地铁上把整张卷子默了一遍。和第一批相比第二批的题型分布、考点侧重点都做了明显调整尤其是把国产数据库、向量数据库、时序数据库这些东西直接塞进了正式考题而不是放在开放性问答里“加分”用。这篇文章不是押题而是基于我实际考下来的回忆梳理把每一类题型的解题思路、踩坑点和值得深挖的知识边界都拆开讲清楚给后面还要考的同学做一个参考。先交代一下整场笔试的基本盘时长120分钟满分100分题型分布为30道单选题、10道多选题、6道简答题、2道SQL编程题外加1道数据库设计场景题。从分值占比来看单选多选合计40分简答30分SQL编程20分场景设计10分。整体不算刁钻但有一个特点非常明显它考的不是“你背了多少概念”而是“你有没有真的在数据库上踩过坑”。比如单选题里出现“MySQL已经有了重复数据再创建唯一索引会怎样”简答题里出现“主从延迟导致读不到刚写入的数据你会怎么处理”这些在只看书不实操的候选人眼里基本就是送命。1. 第二批笔试题型分布与整卷节奏复盘1.1 题型结构与分值占比先给一张我回忆整理的题型分布表方便后面看文章的时候对照题型题量分值占比考察方向单选题30题30分基础概念、隔离级别、索引原理、锁机制多选题10题10分复制同步、备份恢复、高可用方案选型简答题6题30分死锁排查、慢SQL优化、国产数据库适配SQL编程2题20分开窗函数、联表更新、增删改查复杂场景场景设计1题10分订单表设计、时序数据建模、向量检索方案单选题基本控制在1分钟以内一道多选和简答需要多留时间。真正容易超时的是SQL编程代码要手写还要注意语法细节建议至少留30分钟给这两道题。场景设计题虽然只有10分但需要画表结构、写索引设计、说明理由至少留15分钟。1.2 时间分配策略与失分点观察我自己的时间分配方案是单选20分钟、多选15分钟、简答25分钟、SQL编程35分钟、场景设计15分钟最后留10分钟检查。实际做下来单选略有富余简答因为要写排查链路稍微超了一点。从失分点来看几个容易被轻视的地方一是多选里考察了“数据库同步软件”在异构数据源之间的应用场景很多人在“基于日志的实时同步”和“基于触发器的准实时同步”两个选项之间犹豫二是简答题里有一道“如何设计一张订单表来支撑高并发查询”如果平时没有做过反范式设计很容易答成纯范式化的三范式建模反而拿不到分。所以整张卷子给我的感觉是重实战、重场景、重经验这是和单纯背书的笔试最大的区别。2. 基础SQL与增删改查送分题里的“暗坑”2.1 一道“简单”的UNIQUE冲突题已有重复数据如何加唯一索引这批单选里有这么一道题题干很朴素“一张订单明细表里由于历史数据问题同一个订单号出现了多行重复数据。现在业务要求给订单号加唯一索引应该怎么做”选项里有直接ALTER TABLE ADD UNIQUE的、有先DELETE重复再添加的、有先查询重复再用临时表处理的、还有直接不管的。很多人上来就选“先删除重复再添加”但实际上这是有坑的。你直接执行DELETE删哪行保留哪行语义是不确定的。我当时是先在脑子里过了一遍完整流程-- 查看重复数据分布 SELECT order_no, COUNT(*) FROM order_detail GROUP BY order_no HAVING COUNT(*) 1;确认重复范围之后通过主键保留最小ID删除其余重复行DELETE od1 FROM order_detail od1 INNER JOIN order_detail od2 WHERE od1.order_no od2.order_no AND od1.id od2.id;这个方案的逻辑是“每组重复数据里保留最早插入的那一条”虽然业务上不一定是正确的那条但至少可解释、可回滚。做完删除之后再创建唯一索引。为什么不能直接加索引因为MySQL在存在重复数据时执行ALTER TABLE ADD UNIQUE会直接报错不会帮你自动处理。这题的本质是在考唯一索引对存量数据的要求而很多新人只背过“唯一索引能保证唯一性”却没处理过“已经有重复数据时怎么落地”。2.2 EXCEL导入数据库报“外部表不是预期格式”怎么办有一道多选或者操作描述类的题问的是用客户端工具批量导入Excel数据时提示“连接到数据库失败。常规功能故障外部表不是预期的格式”可能的原因有哪些。这个报错我在实际工作里遇到过不止一次。大多数情况下根本不是数据库权限问题而是Excel文件本身的问题。常见原因有三个第一文件并不是真正的.xlsx而是把.csv或者其他文本格式改了后缀名导致驱动解析失败第二Excel文件被WPS或者其他程序打开占用连接读取时拿不到完整文件第三Excel里的列名和表结构不匹配首行表头带了特殊字符或合并单元格。我建议的排查顺序是先看文件签名不要看后缀。用文本编辑器打开文件前几个字符正常的.xlsx文件是PK开头ZIP压缩包格式.csv是纯文本。如果是文本格式直接另存为真正的.xlsx或者改为使用CSV导入方式。另外导入前把目标表结构先建好列名统一用英文字段Excel首行只放英文字段名不要放中文表头能省掉后面一大半的字符集和类型映射问题。2.3 窗口函数与联表更新一道被很多人空着的SQL编程题SQL编程题给了两张表一张是订单表ordersorder_id, user_id, amount, created_at一张是用户表usersuser_id, user_name。题目要求统计每个用户截至当前日期的累计消费金额输出user_name、order_id、amount、截至当前累计金额并按用户分组、按订单时间排序。这道题其实就是标准的SUM窗口函数SELECT u.user_name, o.order_id, o.amount, SUM(o.amount) OVER ( PARTITION BY o.user_id ORDER BY o.created_at, o.order_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cum_sum FROM orders o LEFT JOIN users u ON o.user_id u.user_id ORDER BY u.user_name, o.created_at;注意里面加了一个o.order_id作为ORDER BY的次要排序键这是为了避免同一时刻下多条订单时累计顺序不稳定。部分人直接用GROUP BY加子查询去算结果导致非聚合列没法查出或者查出来性能极差。窗口函数在这个场景下可以说是最优解既解决了“逐行累计”的需求又避免了自连接带来的复杂度。第二道SQL编程题是经典的“联表更新”把一张表中的冗余字段用另一张表的最新值更新这里就涉及MySQL多表UPDATE的语法写错了连接方向或者JOIN条件更新行数直接不可控。3. 索引、执行计划与数据库设计真正拉开差距的部分3.1 联合索引的最左前缀原则为什么不能靠背简答题里有这么一道表t上建了联合索引idx_a_b_ca, b, c问下面哪些查询能走索引哪些不能WHERE a1 AND b2WHERE b2 AND c3WHERE a1 AND c3WHERE a IN (1,2) AND b3。答案很简单第一个能走第二个不能走跳过a第三个只能用到索引中的a列第四个能走。但题目如果只考到这个程度那和背诵没区别。实际阅卷的加分点在“为什么”。联合索引本质上是把多个列拼接成一个有序键在B树里先按a排序a相同再按b排序b相同再按c排序。所以查询条件里如果缺少a索引树的第一层就没办法定位只能全索引扫描或者回表。我答题的时候补了一个平时踩坑的案例一个分页查询条件里只有b和c当时图省事直接在b, c上建了联合索引但因为这个表还有另一个高频查询用a做等值条件最后DBA让我改成a, b, c再用b和c的等值条件去过滤理由是索引的复用性和覆盖范围更优。这个例子说明索引设计不是“建得越多越好”而是要画出所有高频查询的WHERE条件再按等值列在前、范围列在后的原则合并成联合索引。3.2 一条慢查询的完整排查链路这批笔试的简答题里有一道题特别典型一个列表查询接口平时响应50ms某天突然变成3秒表数据量约200万行SQL大概是SELECT * FROM payment WHERE status 1 AND created_at 2023-01-01 ORDER BY id DESC LIMIT 20;问怎么排查。我给了这么一条链路第一步先看慢查询日志和EXPLAIN。EXPLAIN的结果里type是ALLrows扫了接近200万行Extra里有Using filesort说明既没用上索引排序也走了文件排序。第二步检查索引情况。表上只有一个主键索引status和created_at都没有索引。第三步定位核心矛盾status选择性差只有0和1两个值单独建索引意义不大created_at选择性好但直接建created_at, status联合索引排序字段ORDER BY id和查询条件不一致还是可能产生额外的排序。我选择的方案是两条路并行一是改写SQL用子查询先查出满足条件的主键id再回表取详情减少回表行数二是建立覆盖更友好的索引status, created_at, id让排序字段id直接走索引顺序。实测下来查询从3秒降到120ms左右。笔试里如果只答“加索引”三个字基本是不及格因为没体现出对索引选择性和排序方向的分析过程。3.3 反范式设计订单表冗余字段的取舍场景设计题给了一个典型电商场景用户下单后要展示订单列表列表项需要显示用户名、商品名、商品快照图、下单金额。要求设计订单表结构并说明索引方案。如果走纯范式化订单表只存user_id和product_id查询时再去关联用户表和商品表问题在于商品信息是会变的用户改个昵称历史订单里的用户名也跟着变了这在电商场景是业务上不能接受的。所以正确的方向是反范式订单表直接冗余user_name、product_name、product_image这些快照字段下单时把那一刻的信息写进去之后商品表和用户表怎么改都不影响历史订单展示。索引设计上核心查询是“某个用户的订单列表按时间倒序”所以联合索引user_id, created_at DESC是必须的。如果想支持按订单状态筛选可以再加user_id, status, created_at这个联合索引。这里面的设计原则是索引列的先后顺序优先满足等值查询再满足排序需求。同时冗余字段不宜过多一般只冗余展示性字段不要在订单表里冗余“商品库存”这种强一致字段否则更新一致性会非常痛苦。4. 事务隔离级别、锁与死锁高频失分点排查实录4.1 “当前读”和“快照读”同时出现时很多人第一问就错了单选里有一道题描述的是RR隔离级别下事务A先执行了一次SELECT快照读事务B插入了一条新数据并提交事务A再执行一次SELECT还是快照读问事务A能不能看到B插入的数据。这个答案是不能因为RR级别下快照读的ReadView是在第一次SELECT时生成的整个事务期间复用。但如果把第二次SELECT换成SELECT ... FOR UPDATE也就是当前读情况就变了当前读每次都会读取最新的已提交版本所以能读到B插入的数据。这个知识点在多家公司的笔试题里反复出现本质是在考MVCC的ReadView生成机制和当前读/快照读的区别。我在答题时多写了一句RR隔离级别下通过next-key lock解决了幻读问题但只针对当前读快照读依赖的是MVCC两者是两条完全不同的路径。4.2 一个典型的死锁现场还原简答题出了一道死锁分析给了两张表account和account_log两个事务并发执行事务1UPDATE account SET balance balance - 100 WHERE id 1; UPDATE account_log SET remark t1 WHERE log_id 100;事务2UPDATE account_log SET remark t2 WHERE log_id 100; UPDATE account SET balance balance 100 WHERE id 1;这就是教科书级的死锁事务1持有id1的行锁申请log_id100的行锁事务2持有log_id100的行锁申请id1的行锁。MySQL的死锁检测机制发现循环等待会选择回滚其中一个事务。我在答题时特别强调了加锁顺序一致性所有事务对多个资源的加锁顺序必须一致比如都先操作account再操作account_log死锁就不会发生。实际项目里这种问题很难通过代码审查发现因为两个事务写在不同的服务模块里只有在压力测试或者线上流量高峰才会触发。4.3 排查死锁的正确顺序从information_schema到SHOW ENGINE INNODB STATUS如果笔试题让你“排查数据库死锁”不要只答“innodb死锁自动回滚一个事务”。完整的排查链路应该是第一步开启死锁日志或者查看最近一次死锁信息SHOW ENGINE INNODB STATUS\G重点看LATEST DETECTED DEADLOCK部分里面有具体的事务ID、等待的锁、持有的锁、涉及的SQL语句。第二步通过performance_schema.data_locks和data_lock_waits视图定位当前正在等待锁的事务找出两个事务各自的资源占用情况。第三步根据日志里的事务SQL还原事务加锁顺序确定死锁根因。第四步给出修复方案常见的有调整SQL加锁顺序、缩小事务范围、降低隔离级别从RR降到RC、对高频更新行做串行化改造或者利用重试机制处理被回滚的事务。这道题能拿多少分关键就看你能不能把“查到死锁日志到定位到具体SQL再到修复”这一段完整地说出来。如果只停留在概念层面阅卷人一眼就看出来你没真处理过线上问题。5. 高可用、主从同步与国产数据库适配第二现场的运维题5.1 主从延迟的三种常见成因与“读己之写”问题简答题里有一道做了读写分离之后用户下单成功后立刻跳转到订单详情页结果偶发显示“订单不存在”问原因和解决方案。这个场景在互联网公司太常见了。原因是主库写入成功但从库同步有延迟读请求路由到了从库从库还没拿到这条最新数据。深挖下去无非三个成因一是主库大事务比如一次性更新几万行导致binlog在从库回放时间过长二是从库硬件性能弱于主库单线程复制跟不上主库的多线程写入三是从库上有大量查询在跑挤占了SQL线程的资源。我的回答分两层。第一层是缓解方案把核心的订单详情查询强制路由到主库或者引入“读己之写”机制在会话级别标记最近写入时间短时间内走主库。第二层是治本方案主库避免大事务拆批提交从库开启并行复制MTS降低从库上的非核心查询负载。这里我还提了一个生产环境常见的补充如果延迟实在压不下来可以考虑把订单写入和订单查询放在同一个数据库实例只对非核心的统计类查询做读写分离。这是在一致性和性能之间做的取舍笔试里能体现这种取舍意识会加分。5.2 国产数据库适配题Nacos适配GaussDB这类题到底在考什么这批笔试里出了不少与国产数据库相关的题目印象比较深的是一道“Nacos使用GaussDB作为存储数据库做适配需要修改哪些配置”的题。这题表面考的是国产数据库实际上考的是一个非常通用的能力中间件对接外部数据库时需要替换驱动、方言和连接配置。Nacos默认使用的是Derby或MySQL如果要换成GaussDB等国产数据库需要关注几个点驱动类名、JDBC URL格式、数据库方言实现、以及默认的表结构初始化脚本。在GaussDB这类基于openGauss生态的数据库上驱动通常可以使用对应的PostgreSQL兼容驱动或专用驱动URL需要带上目标schema。我当时的答题思路是先给出探查步骤再给关键配置示例而不是死记某一段配置。关于“达梦数据库如何开启CDC”这类题我的答法是达梦开启CDC需要先开启数据库归档模式然后通过DM的CDC工具配置捕获器指定要捕获的表最后通过指定的用户权限来读取变更日志。实际操作中大多数国产数据库的CDC能力本质上还是基于数据库日志解析原理和MySQL的binlog、PostgreSQL的WAL没有本质区别掌握了底层机制适配新数据库时就不会慌。5.3 人大金仓、达梦的“数据库课程设计”类背景题有一道多选考的是“在课程设计项目中选用人大金仓数据库并用Docker部署遇到数据持久化问题怎么解决”。这个题说出来可能觉得有点怪但确实考了。它的核心点是数据库容器化部署时数据目录必须挂载到宿主机持久化卷否则容器重启后数据丢失。大部分人金仓、达梦的Docker镜像默认数据目录在容器内部如果不挂载docker rm之后数据全没了。解决方法是启动容器时加-v参数把数据库数据目录映射到宿主机docker run -d \ --name kingbase \ -v /data/kingbase:/var/lib/kingbase \ -p 54321:54321 \ kingbase:latest这题提醒了一个很现实的问题现在很多高校的课程设计和企业内部试点都在用国产数据库数据库从业者不能只盯着MySQL和Oracle对达梦、人大金仓、GaussDB这类数据库的基本安装、Docker部署、CDC开启、驱动配置这些操作步骤也要有所了解。这不是政治正确的问题是实实在在的岗位需求。6. 备份恢复、审计与数据库安装容易被忽略的实战细节6.1 开启审计导致索引争用一道充满矛盾感的题单选里有一道题题干说“某系统开启数据库审计之后业务高峰期出现明显的索引争用SQL执行变慢分析原因”。这题答起来很有意思审计本来是为了安全结果反而拖垮了性能。审计日志的写入本质上是高频顺序IO但它的写入位置和业务索引在同一个InnoDB表空间里审计表本身如果也有索引那么每产生一条审计日志都要更新索引加上业务表的高频DML必然加剧索引页的争用与刷盘压力。解决方向有三个把审计表放到独立的表空间和独立磁盘减少审计记录范围只审计关键操作使用异步审计队列把审计日志写入和业务事务解耦。还有一个更彻底的方案就是审计日志直接写到外部日志系统数据库层只保留必要的安全审计项。这道题考的不是背书而是你能不能识别“安全与性能之间的冲突”并给出可执行的平衡方案。6.2 Oracle安装与pgsql实例启动两道“环境类”题这批笔试还出现了两道偏环境的题一个是“Oracle数据库安装和配置时最常见的失败原因有哪些”另一个是“PostgreSQL数据库实例的启动方式有哪些”。Oracle安装的常见失败点我总结过一是安装前没有检查系统的swap空间和内核参数导致DBCA建库时内存检查不过二是没有创建独立的oracle用户和用户组直接用root安装导致权限问题三是缺少必要的系统依赖库图形界面起不来。我在答题时重点提了Oracle安装前的那份“环境预检清单”包括内核参数kernel.sem、kernel.shmall、fs.file-max等。这方面没有捷径只能按官方文档一步步来。PostgreSQL启动方式的题核心是pg_ctl命令体系pg_ctl start启动实例、pg_ctl stop停止、pg_ctl restart重启、pg_ctl reload重载配置。启动时可能遇到的问题包括postmaster.pid文件残留导致端口占用报错、数据目录权限不对、共享内存大小不够等。实际处理时看到“PID file exists”的报错不要急着删文件要先确认是不是真的没有实例在运行用ps和ss检查端口再决定是否清理残留文件。这个排查顺序很多新手不知道容易误杀正在运行的实例。6.3 备份恢复策略从全量备份到增量备份的恢复时限计算笔试计算题里有一道长这样某系统每天晚上12点做全量备份每2小时做一次增量备份某个周三上午10点数据库发生故障问恢复到故障点最多需要应用多少增量日志以及RPO大概是多少。这个计算的关键在于时间线。周三上午10点故障上一次全量备份是周三0点之后每2小时做一次增量备份也就是2点、4点、6点、8点各有一次增量备份。10点发生故障时从8点的增量备份到10点之间的数据只能依赖归档日志或者binlog来恢复这部分数据的丢失窗口就是RPO最多接近2小时。如果业务要求RPO在15分钟内就需要把增量备份频率提高到每15分钟一次或者依赖实时的binlog同步到备库。这道题考的是备份策略与RPO/RTO之间的换算关系核心公式就是RPO约等于“最近一次可恢复时间点”到“故障时间点”之间的间隔。我答题时把恢复流程也写了一遍先恢复最近的全量备份再按时间顺序依次应用增量备份最后应用归档日志到目标时间点。7. 开放题与前沿方向向量数据库和时序数据库的设计思路7.1 向量数据库为什么会被单独拎出来考第二批笔试里有一道开放题问“在智能客服场景中如何基于向量数据库做历史工单的相似问题召回”。这题不是让你写代码而是考察对向量化检索链路是否完整。我的答题思路分了四步第一步把历史工单的问题文本通过Embedding模型转成向量存入向量数据库第二步用户提新问题时同样调用Embedding接口转成查询向量第三步向量数据库执行近似最近邻检索ANN按余弦相似度或内积相似度返回TopK的相似工单第四步把检索结果交给下游排序模型重排后展示给客服人员。这里我特意提了索引选型如果数据量在百万级HNSW足够千万级以上考虑IVF加PQ的组合但在召回率和延迟之间要做权衡。这道题能考出来说明出题方已经不满足于“你懂不懂MySQL”而是要求候选人知道向量数据库在AI应用中的位置。结合行业趋势RAG检索增强生成是当前落地最多的架构向量数据库是其中不可缺少的组件。我没有在这题上花太多时间但把链路讲清楚了比堆概念要有效得多。7.2 时序数据库的库表结构怎样设计最后一道开放题是“设计一个设备监控场景的时序数据库表结构采集项包括设备ID、温度、湿度、采集时间”。这不是让你用InfluxDB或者Prometheus的现成语法写而是让你从数据库设计角度去拆解。时序数据的核心特点有三个写多读少、按时间范围聚合、数据量极大。所以表结构不能按传统关系型范式来。我当时的设计思路是用一张“指标宽表”存储采集点核心字段是设备ID、采集时间、指标名、指标值再加上一组标签字段机房、区域、设备类型。设备ID和时间组成联合主键。为了支撑按时间范围查询必须按时间分区比如按天或者按小时分区。为了控制存储成本还要设计降采样和过期清理策略比如原始数据保留7天聚合数据保留30天。这个设计题其实没有标准答案但能考察你能不能抓住时序场景和OLTP场景的本质区别。最忌讳的是拿订单表那套范式化设计直接套上去把每个采集指标建一张表。读到这里的同学即使没做过时序数据库也建议自己找一个物联网设备数据集用常见的时序数据库从零建一次表、做一次查询这个经验在笔试里比任何概念都有说服力。8. 考前怎么准备以及我对这次笔试的整体感受第二批笔试总体难度比第一批略高高在场景题和运维题的比例上。第一批还有不少纯概念题第二批几乎每个知识点都挂了一个业务场景比如“读写分离后读不到数据”“Excel导入报错”“审计拖垮性能”。这说明出题方真正想筛选的是那些在实际工作中遇到过问题、并且会主动复盘的人。如果你准备参加类似的春招笔试我的建议是第一把MySQL的索引、锁、事务隔离级别、主从同步这四块吃透它们占了整张卷子至少一半的分值第二对国产数据库达梦、人大金仓、GaussDB不需要掌握得太深但至少要会装、会配驱动、会Docker部署第三向量数据库和时序数据库不用背API但要把“为什么需要这类数据库”和“核心数据结构怎么设计”讲清楚第四做题时遇到SQL题一定要手写出来不要只在脑子里过一遍语法细节只有在落笔时才会暴露问题。我自己的体会是这类笔试不是靠考前突击一周就能过的它考的更多是你在日常工作中养成的排查习惯和知识沉淀。比如“遇到死锁先看SHOW ENGINE INNODB STATUS”这种下意识反应只有在真实环境里处理过几次才会刻进脑子里。如果你还在校或者刚入行建议多找机会折腾一下真实的数据库环境包括没事导入几万行数据试试索引和性能或者搭一套主从复制故意制造延迟来观察现象。这些都是笔试里最有含金量的素材比背一百道面试题都管用。