为什么 MSSQL(SQL Server)要预占内存,以及 预占之后业务是如何使用/分配的。
预占内存→ 保证性能和稳定性,避免频繁向操作系统申请内存。内部划分→ Buffer Pool、Plan Cache、Query Execution Memory、锁/上下文等组件共享使用。业务分配→ 查询通过 Memory Grant 框架向 SQL Server 内部分配,缓存和执行空间动态调整。要不要我帮你画一个MSSQL 内存分配流程的 Mermaid 流程图(比如从 OS → SQL Se
·
目录标题
你问得很专业 👍,我来系统解释一下 为什么 MSSQL(SQL Server)要预占内存,以及 预占之后业务是如何使用/分配的。
1. MSSQL 为什么要预占内存?
SQL Server 启动后,会根据配置和当前系统资源 申请并预留一部分内存,这部分内存不会轻易还给操作系统。主要原因是:
-
性能考虑
- 避免频繁的 OS 层面内存分配/释放,减少系统调用开销。
- 数据库往往需要快速响应,频繁向操作系统要内存会增加延迟。
-
缓存机制
- SQL Server 内部的 Buffer Pool(缓冲池)用来缓存数据页(8KB 页)。
- 如果不预先占用足够的内存,缓冲池无法稳定缓存更多热数据,会导致频繁磁盘 I/O。
-
可控性
- DBA 可以通过
min server memory
和max server memory
控制 SQL Server 的内存使用范围。 - SQL Server 会尽可能接近
max server memory
,避免被 OS 抢占,保证数据库的内存优先级。
- DBA 可以通过
2. 预占之后,SQL Server 内部如何分配?
SQL Server 把预占的内存分为几个内部组件来使用:
(1)Buffer Pool(缓冲池,核心)
- 最大的内存使用者。
- 缓存 数据页(Data Pages)、索引页(Index Pages),减少磁盘读取。
- 查询需要访问数据时,会优先从缓冲池读取。
- 写数据时,先写入缓冲池中的 脏页(Dirty Pages),再由后台 Checkpoint/Lazy Writer 刷回磁盘。
(2)Plan Cache(执行计划缓存)
- 保存 SQL 编译后的执行计划。
- 避免每次执行 SQL 都重新编译。
- 内存不足时,会按照 LRU(最近最少使用)淘汰旧计划。
(3)Query Execution Memory(查询执行内存)
-
用于 排序(Sort)、哈希连接(Hash Join)、索引创建 等操作的临时工作区。
-
分配方式:
- 先向 内存授予机制(Memory Grant Framework) 申请。
- 如果内存不足,会触发 查询等待(RESOURCE_SEMAPHORE 等待类型)。
(4)其他内部组件
- Lock Manager:用于锁信息存储。
- Connection Context:会话上下文信息。
- Columnstore/Object Pool:列存储索引、In-Memory OLTP 的内存使用。
3. 内存使用过程(业务层面)
举个例子,业务执行一个 SQL 查询时,SQL Server 内存分配大致过程是:
-
解析与编译
- 查询语句进入解析器,编译后存入 Plan Cache。
- 如果计划已存在,则直接复用,不需要额外内存。
-
执行阶段
-
如果需要访问数据页,先查 Buffer Pool:
- 命中:直接读取缓存,不额外占用内存。
- 未命中:从磁盘读入 8KB 页,放到 Buffer Pool。
-
-
执行运算(如排序/哈希)
- 向 Query Execution Memory 申请一块内存(Memory Grant)。
- 如果内存不足,查询会排队等待(出现
RESOURCE_SEMAPHORE
等待事件)。 - 分配成功后,查询在内存中处理数据。
-
返回结果 / 写数据
- 数据修改写入 Buffer Pool 中的页,标记为 Dirty Page。
- 后台写入磁盘(异步)。
4. 总结
- 预占内存 → 保证性能和稳定性,避免频繁向操作系统申请内存。
- 内部划分 → Buffer Pool、Plan Cache、Query Execution Memory、锁/上下文等组件共享使用。
- 业务分配 → 查询通过 Memory Grant 框架向 SQL Server 内部分配,缓存和执行空间动态调整。
要不要我帮你画一个 MSSQL 内存分配流程的 Mermaid 流程图(比如从 OS → SQL Server → 内部组件 → 业务查询的分配过程),方便直观理解?
更多推荐
所有评论(0)