Skip to content

SQL Server 架构:数据库引擎的「三权分立」

你有没有想过,一条 SELECT 语句从客户端发出,到最终返回结果,SQL Server 内部经历了什么?

很多人只会说「查询数据库」。但如果你追问:连接怎么建立?语法怎么解析?数据怎么从磁盘到内存?十个人里有九个答不上来。

今天,我们来揭开 SQL Server 架构的神秘面纱。

数据库引擎的三层架构

SQL Server 数据库引擎可以分为三层:关系引擎存储引擎、和 SQL OS。每一层各司其职,缺一不可。

┌─────────────────────────────────────────────────────────┐
│                    关系引擎(Relational Engine)          │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────────┐   │
│  │ 命令解析  │→ │ 查询优化  │→ │ 执行计划生成         │   │
│  └──────────┘  └──────────┘  └──────────────────────┘   │
└────────────────────────┬────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│                    存储引擎(Storage Engine)              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌───────┐ │
│  │ 访问方法 │  │ 锁管理   │  │ 日志管理  │  │ 缓冲池 │ │
│  └──────────┘  └──────────┘  └──────────┘  └───────┘ │
└────────────────────────┬────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│                    SQL OS                                │
│  调度器、内存管理、同步机制、 Worker 线程池               │
└─────────────────────────────────────────────────────────┘

关系引擎:数据库的「大脑」

关系引擎负责处理查询请求,核心组件包括:

命令解析器(Parser) 负责将 T-SQL 语句转换为解析树,检查语法错误,生成逻辑操作符。

绑定器(Binder) 将解析树与系统目录关联,检查对象是否存在、权限是否足够,生成查询的内部表示。

查询优化器(Optimizer) 是关系引擎最复杂的部分。它会根据统计信息生成多个执行计划,选择成本最低的那个。这里有个面试常考点:优化器生成的执行计划一定是最优的吗? 答案是否定的,因为优化器使用的是启发式算法,时间有限,不可能穷尽所有方案。

执行引擎(Executor) 按照执行计划一步步执行,从存储引擎请求数据,组装结果集返回。

存储引擎:数据的「仓库管理员」

存储引擎负责数据的物理存储和访问,核心组件包括:

访问方法(Access Methods) 提供读写数据的接口,包括堆表、聚集索引、非聚集索引的访问方式。

锁管理器(Lock Manager) 负责实现事务隔离级别,处理并发控制。你在事务与锁概览中会详细了解。

日志管理器(Log Manager) 确保事务的持久性,记录所有修改操作。事务日志是 SQL Server 恢复能力的基石。

缓冲池(Buffer Pool) 是 SQL Server 的内存核心,缓存数据页和执行计划。数据不会直接从磁盘读取,而是先加载到缓冲池。

SQL OS:底层调度员

SQL OS 是 SQL Server 2008 引入的组件,位于 Windows 操作系统和数据库引擎之间,提供:

任务调度 基于 Windows SOS(SQLOS)的调度器,将 worker 线程映射到 CPU 逻辑核心。每个调度器负责特定 CPU 核心,worker 交替执行。

内存管理 统一管理数据库引擎各组件的内存分配,避免内存碎片化。

同步原语 提供 latch、spinlock 等底层同步机制。

查询执行的整体流程

了解了三层架构,我们来看一条查询的完整旅程:

java
/**
 * SQL Server 查询执行流程(简化模型)
 * 实际执行远比这复杂,包含并行执行、分布式查询等
 */
public class QueryExecutionFlow {
    
    /**
     * 模拟 SQL Server 查询处理流程
     * 
     * @param sql 用户提交的 SQL 语句
     * @return 查询结果
     */
    public Object executeQuery(String sql) {
        // 第一阶段:连接管理
        // TDS 协议建立会话,验证身份,设置环境选项
        ConnectionHandler handler = establishConnection(sql);
        
        // 第二阶段:解析与绑定
        // 语法检查 → 生成解析树 → 绑定对象和权限
        ParseTree tree = Parser.parse(sql);
        BoundTree bound = Binder.bind(tree);
        
        // 第三阶段:查询优化
        // 生成候选计划 → 估算成本 → 选择最优计划
        ExecutionPlan plan = Optimizer.optimize(bound);
        
        // 第四阶段:执行计划
        // 缓冲区查找或磁盘读取 → 数据处理 → 结果组装
        ResultSet result = Executor.execute(plan);
        
        // 第五阶段:返回结果
        // 通过 TDS 协议返回客户端
        return sendResult(result);
    }
}

协议层:客户端与服务端的对话

SQL Server 使用 TDS(Tabular Data Stream)协议 进行客户端与服务端的通信。你平时用的 SSMS、JDBC、ADO.NET,背后都是 TDS 在工作。

TDS 会话生命周期:

  1. 建立连接 - 客户端发送登录包,服务端验证用户名密码
  2. 执行命令 - 客户端发送 SQL 命令,服务端返回结果
  3. 断开连接 - 释放资源,清理会话状态

有意思的是,JDBC 连接 SQL Server 时,驱动会帮你封装 TDS 协议的细节。但如果你想排查连接问题,了解这个协议会很有帮助。

内存结构:数据页的缓存池

SQL Server 的内存使用遵循一个原则:能用内存就不访问磁盘

缓冲池(Buffer Pool)是 SQL Server 的核心内存区域,结构如下:

┌─────────────────────────────────────────┐
│            Buffer Pool                    │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐     │
│  │ Page 1  │ │ Page 2  │ │ Page 3  │ ... │
│  │ (数据)  │ │ (数据)  │ │ (索引)  │     │
│  └─────────┘ └─────────┘ └─────────┘     │
│         每个 Page 大小:8KB                │
└─────────────────────────────────────────┘

数据页是 SQL Server 最基本的存储单位,大小固定为 8KB。当查询需要某行数据时:

  1. 检查该页是否在缓冲池中
  2. 如果在(命中),直接读取
  3. 如果不在(未命中),从磁盘读取并放入缓冲池
  4. 如果缓冲池满了,触发页面置换算法(LRU)

这就是为什么数据库服务器内存越大,性能通常越好——能缓存更多数据页,减少磁盘 I/O。

进程架构:从开放数据服务到 SQL Server

在早期版本中,SQL Server 使用 MSSQLServerSQLServerAgent 两个 Windows 服务进程。

从 SQL Server 2005 开始,引入了开放数据服务(Open Data Services,ODS)架构,将监听、连接管理、查询处理等拆分为独立组件:

┌────────────────┐    ┌────────────────┐
│ 客户端应用     │ ←→  │ TDS 监听器     │
└────────────────┘    └───────┬────────┘

                    ┌────────────────┐
                    │ 连接管理器      │
                    └───────┬────────┘

                    ┌────────────────┐
                    │ 查询处理器      │
                    └───────┬────────┘

                    ┌────────────────┐
                    │ 存储引擎        │
                    └────────────────┘

这种架构让 SQL Server 能够更高效地管理数千个并发连接。

总结

SQL Server 架构可以用三句话概括:

  1. 关系引擎负责「想」——解析、优化、生成执行计划
  2. 存储引擎负责「做」——读写数据、管理事务、控制并发
  3. SQL OS负责「调度」——分配 CPU 时间片、管理内存、协调各组件

理解这个架构,是深入学习 SQL Server 的前提。


面试追问方向:

  • 为什么 SQL Server 使用 8KB 作为数据页大小?这个值可以调整吗?
  • 如果缓冲池满了,SQL Server 如何决定将哪些页面换出?什么是 Checkpoint?
  • SQL Server 和 MySQL 在架构上有什么本质区别?

这些追问的答案,都在后续章节中。

基于 VitePress 构建