Skip to content

SQL Server 面试高频问题汇总

经过前面的学习,你已经掌握了 SQL Server 的核心知识点。

这篇文章,帮你梳理面试中高频考察的问题,以及如何给出让人眼前一亮的答案。


一、架构与存储

Q1:SQL Server 的整体架构是怎样的?

参考答案

SQL Server 由两层引擎组成:关系引擎负责解析、优化和执行 SQL,存储引擎负责数据的物理存储和读写。

关系引擎包含:命令解析器、查询优化器、执行引擎。存储引擎包含:访问方法、缓冲池、事务管理器、锁管理器。

两者协作:关系引擎生成执行计划,调用存储引擎的接口完成数据读写。

加分回答

  • 缓冲池是 SQL Server 的核心内存组件,缓存数据页
  • 执行引擎支持行模式和批处理模式,后者配合列存储索引可大幅提升分析性能

Q2:SQL Server 的页和区是什么?

参考答案

SQL Server 的存储单位:页(Page)= 8KB,区(Extent)= 8 个连续的页 = 64KB。

页是 SQL Server 最小的 I/O 单位,用于存储数据行和索引结构。区是分配的最小单位,8 个页组成一个区。

有两种区类型:统一区(Uniform)和混合区(Mixed),新对象先用混合区分配一页,8 页后切换为统一区。

面试追问

  • 页头占 96 字节,数据区 8096 字节
  • 行溢出(Row Overflow)发生在行超过 8060 字节时

Q3:什么是文件组?如何设计?

参考答案

文件组是 SQL Server 的逻辑存储单元,将一个或多个数据文件组织在一起。

主文件组(PRIMARY)包含主数据文件和系统表,用户可创建辅助文件组将数据分散到不同磁盘。

设计原则:

  • 热数据放 SSD,冷数据放 HDD,降低成本
  • 大表分区放不同文件组,支持独立的备份和恢复
  • 日志文件不要放在数据文件同一磁盘

二、索引与查询

Q4:聚集索引和非聚集索引的区别?

参考答案

聚集索引决定数据的物理存储顺序,一张表只能有一个聚集索引,叶子节点直接存储行数据。

非聚集索引独立于表数据,叶子节点存储索引键和聚集键(书签),查询时需要回表。

核心区别

特性聚集索引非聚集索引
数量1 个多个
叶子节点存储行数据存储键值 + 书签
适用主键查询加速
回表不需要可能需要

加分回答

  • 聚集键应选择:唯一、简短、稳定、顺序增长
  • 自增 ID 比 UUID 更适合做聚集键(减少页分裂)

Q5:什么是覆盖索引?

参考答案

覆盖索引 = 查询所需的所有列都包含在索引中,无需回表。

通过 INCLUDE 子句将查询需要的列(非索引键)包含在非聚集索引中:

sql
CREATE NONCLUSTERED INDEX IX_Orders_Customer_Covering
ON Orders(customer_id)
INCLUDE (order_no, order_date, total_amount);

适合场景:高频查询少量列,避免 Key Lookup 开销。

Q6:执行计划中 Index Scan 和 Index Seek 的区别?

参考答案

Index Seek(索引查找):利用索引定位,O(log n),适合高选择性查询(返回少量行)。

Index Scan(索引扫描):遍历整个索引,O(n),适合返回大量行或需要大部分列的情况。

优化器选择依据:统计信息估算的返回行数 vs 索引覆盖情况。


三、事务与锁

Q7:SQL Server 的隔离级别有哪些?

参考答案

隔离级别脏读不可重复读幻读
READ UNCOMMITTED
READ COMMITTED
READ COMMITTED SNAPSHOT
REPEATABLE READ
SERIALIZABLE
SNAPSHOT

关键点

  • 默认隔离级别是 READ COMMITTED
  • RCSI 使用行版本而非锁,避免阻塞
  • SNAPSHOT 提供事务级一致性,但可能有更新冲突

Q8:什么是死锁?如何避免?

参考答案

死锁 = 两个或多个事务互相持有对方需要的锁,形成循环等待。

四个必要条件:互斥、占有并等待、不可抢占、循环等待。破坏其中任一条件即可防止死锁。

避免策略

  1. 统一资源访问顺序
  2. 使用 UPDLOCK 提示预锁定
  3. 减少事务持续时间
  4. 创建合适的索引(减少锁粒度)
  5. 使用快照隔离避免写-写冲突

Q9:乐观锁和悲观锁的区别?

参考答案

悲观锁:提前加锁,读取时就锁定,冲突在实际更新时不会发生。

乐观锁:最后检测,读取时不加锁,更新时检查数据是否被修改。

SQL Server 实现方式:

  • 悲观锁:SELECT ... WITH (UPDLOCK)
  • 乐观锁:版本号字段或行版本(快照隔离)

选择原则

  • 冲突概率低 → 乐观锁(并发高)
  • 冲突概率高 → 悲观锁(一致性要求高)

四、性能优化

Q10:如何分析慢查询?

参考答案

分析慢查询的流程:

  1. 开启 STATISTICS IO/TIME
  2. 查看执行计划
  3. 识别问题:全表扫描、回表过多、隐式类型转换
  4. 针对性优化

常见问题

  • 索引失效:函数包裹索引列、OR 条件、类型不匹配
  • 回表过多:Key Lookup,添加覆盖索引
  • 统计信息不准:UPDATE STATISTICS

Q11:什么是统计信息?为什么重要?

参考答案

统计信息描述表中数据的分布,帮助优化器估算执行计划的成本。

包含:直方图(列值分布)、密度向量(列组合密度)、字符串统计。

统计信息不准确 → 优化器选错执行计划 → 查询变慢。

维护策略

  • 自动更新:默认开启,20% 行变化触发
  • 大批量导入后手动更新:UPDATE STATISTICS WITH FULLSCAN

Q12:什么是参数嗅探问题?

参考答案

参数嗅探 = 第一次执行的参数值被用于编译执行计划,后续不同参数可能不适合该计划。

解决方案:

  1. OPTION (RECOMPILE):每次执行重编译
  2. OPTION (OPTIMIZE FOR @var = ?):使用指定值编译
  3. 使用局部变量绕过嗅探
  4. 启用强制参数化(慎用)

五、高可用

Q13:Always On 和 FCI 的区别?

参考答案

特性Always On AGFCI
保护级别数据库组实例级
存储不需要共享存储必须 SAN
读写分离
副本数量最多 8 个1
跨机房灾备
最低版本SQL 2012+ Enterprise所有版本

选择原则

  • 需要读写分离 → Always On
  • 只需要实例级保护 → FCI
  • 两者结合:FCI 节点上部署 Always On,双重保护

Q14:同步提交和异步提交的区别?

参考答案

同步提交(SYNCHRONOUS_COMMIT):主副本写入日志后,等待所有辅助副本确认才提交。RPO = 0(零数据丢失),但有网络延迟。

异步提交(ASYNCHRONOUS_COMMIT):主副本写入日志后立即提交,不等待辅助副本。可能有数据丢失(RPO > 0),但无延迟。

配置建议

  • 本地高可用:同步 + 自动故障转移
  • 异地灾备:异步副本

Q15:什么是 RPO 和 RTO?

参考答案

RPO(Recovery Point Objective)= 最大可容忍的数据丢失时间。

RTO(Recovery Time Objective)= 从故障恢复到业务可用的时间。

计算示例

  • 每小时日志备份 → RPO ≤ 1 小时
  • 完整备份 1TB → RTO 约 3-4 小时
  • Always On 同步副本 → RPO = 0,RTO < 30 秒

六、备份恢复

Q16:三种恢复模式的区别?

参考答案

恢复模式日志备份恢复到时间点适用场景
FULL需要生产环境
BULK_LOGGED需要部分大批量导入
SIMPLE不需要开发/测试

关键点

  • FULL 模式:日志必须定期备份,否则无限增长
  • SIMPLE 模式:检查点时自动截断日志
  • BULK_LOGGED:最小化日志,但不支持 Point-in-Time 恢复

Q17:完整备份、差异备份、日志备份的区别?

参考答案

完整备份:备份整个数据库,记录备份开始时的状态。

差异备份:备份自上次完整备份以来的所有更改,比完整备份小,恢复时需要「完整 + 差异」。

日志备份:备份事务日志,只适用于 FULL/BULK_LOGGED 模式,支持 Point-in-Time 恢复。

恢复顺序

  • 完整 + 日志:完整备份 → 日志备份 1 → 日志备份 2
  • 完整 + 差异 + 日志:完整备份 → 最新差异 → 日志备份

七、综合问题

Q18:如何设计一个订单系统的数据库?

参考答案

核心表设计:

  • Orders:订单主表,聚集索引在 order_id(自增)
  • OrderItems:订单详情,复合聚集索引 (order_id, item_id)
  • Customers:客户表,聚集索引在 customer_id
  • Products:商品表,聚集索引在 product_id

索引设计:

  • 订单查询:IX_Orders_Customer_Date (customer_id, order_date)
  • 客户订单:IX_Orders_Customer (customer_id)
  • 订单统计:覆盖索引包含统计列

高可用设计:

  • Always On 可用性组(同步副本 × 2,异步副本 × 1)
  • 读写分离:读操作路由到辅助副本

备份策略:

  • FULL 恢复模式
  • 每日完整备份 + 每小时日志备份
  • RPO ≤ 1 小时,RTO ≤ 30 分钟

Q19:SQL Server 和 MySQL 的核心区别?

参考答案

方面SQL ServerMySQL
存储单位页 8KBInnoDB 页 16KB
索引结构B-TreeB+Tree(InnoDB)
聚集索引1 个每表 1 个(InnoDB)
事务日志LDF(WAL)redo log + undo log
高可用Always On主从 + MGR
平台Windows/Linux跨平台
SQL 语法T-SQLMySQL 语法

架构差异

  • SQL Server:关系引擎 + 存储引擎分离
  • MySQL:Server 层 + 存储引擎插件化

面试技巧

1. 回答要有层次

每个问题至少三个层次:

  • 基础层:是什么、怎么做
  • 原理层:为什么这样设计
  • 实战层:遇到过什么问题、如何解决

2. 善用对比

对比是展现深度的最好方式:

  • 聚集 vs 非聚集索引
  • 悲观 vs 乐观锁
  • 同步 vs 异步提交
  • Always On vs FCI

3. 留有钩子

在回答的结尾留一个思考点:

「这里有个有意思的点……」

「如果你感兴趣,我可以展开讲……」

4. 用数据说话

「RPO = 0」

「延迟 < 30 秒」

「提升 10-100 倍」


下一步

恭喜你完成了 SQL Server 模块的学习!

如果想继续深入,可以回顾各个章节的重点内容,或者开始其他模块的学习:

基于 VitePress 构建