SQL Server数据库服务器内存问题排查

前言

最近我公众号小伙伴反馈数据库服务器爆满如何处理!接下来我详细解答一下处理方案和预防方案。

SQL Server数据库服务器内存占用高是普遍情况,不用过于紧张,因为几乎所有涉及的数据库为了加快数据库的执行效率都会缓存一部分数据到内存,如果服务器还有剩余内存,通常不用慌。如果经常内存爆满导致服务器异常那就另当别论了。

一、 立刻处理(快速释放、恢复)

  1. 清除缓存(谨慎使用,仅在紧急时)
    这会清空缓存,可能导致瞬间性能波动,业务低峰期操作。

    sql 复制代码
    DBCC FREESYSTEMCACHE ('ALL'); 
    DBCC FREEPROCCACHE; 
  2. 杀掉阻塞/耗时查询
    先找出耗资源的会话,手动 Kill。

    sql 复制代码
    -- 查看耗时且占用高的会话(为啥限制大于50是因为2005之前系统会话ID都小于等于50)
    SELECT session_id, status, command, wait_type 
    FROM sys.dm_exec_requests 
    WHERE session_id > 50;
    
    -- 杀掉会话(替换 SPID)注意一定不要误杀 有些属于系统会话(比如写日志、清理)
    KILL 56; 

二、 根源排查

  1. 确认内存使用情况

    sql 复制代码
      -- 查看数据库内存使用
       SELECT 
           (physical_memory_in_use_kb / 1024) AS SQL_Server_Used_Memory_MB,
           (locked_page_allocations_kb / 1024) AS SQL_Server_Locked_Pages_MB,
           (total_virtual_address_space_kb / 1024) AS Total_Virtual_Address_Space_MB,
           process_physical_memory_low,
           process_virtual_memory_low
       FROM sys.dm_os_process_memory;
       --查看服务器内存使用
         SELECT 
           (total_physical_memory_kb / 1024) AS Total_OS_Memory_MB,
           (available_physical_memory_kb / 1024) AS Available_OS_Memory_MB,
           system_memory_state_desc
       FROM sys.dm_os_sys_memory;
    • 结论 :如果 Available_OS_Memory_MB 还很大,说明这只是SQL占满了缓冲池,是正常现象;如果可用内存极少,服务器甚至Swap分区爆满,才需要紧急优化。*
      顺便提一下,不要使用任务管理器来查看 SQL Server 的内存使用情况,它显示的值往往不准确。这是因为如果 SQL Server 启用了"锁定内存页"权限,大部分内存分配会通过 AWE API 进行,这部分内存不会在任务管理器的"进程私有字节"中显示,从而导致你看不到真实的内存占用。使用上述 DMV 查询才能获得准确的数据。
  2. 定位是谁在"吃内存"

    sql 复制代码
    -- 按数据库统计内存占用
    SELECT 
        DB_NAME(database_id) AS DatabaseName,
        COUNT(*) * 8/1024 AS CacheSize_MB
    FROM sys.dm_os_buffer_descriptors
    GROUP BY DB_NAME(database_id)
    ORDER BY CacheSize_MB DESC;
    GO

三、 永久优化方案(稳定运行)

  1. 配置最大内存(关键!)
    防止SQL Server抢光系统内存导致Windows或其他服务挂掉。

    sql 复制代码
    sp_configure 'show advanced options', 1; RECONFIGURE;
    sp_configure 'max server memory (MB)', 32768; -- 假设机器64G,留32G给系统和其他程序
    RECONFIGURE;
  2. 索引与查询优化
    内存高大多是因为全表查询、缺失表索引、滥用函数、查询大字段数据导致的。

    • 重建/重组索引
    sql 复制代码
    -- 检查碎片
    DBCC SHOWCONTIG ('表名');
    -- 重组(碎片<30%)或重建(碎片>30%)
    ALTER INDEX ALL ON 表名 REBUILD;
  • 清理执行计划缓存:解决参数嗅听问题。
sql 复制代码
DBCC FREEPROCCACHE;

四、 监控预警建议

建议在服务器上建个作业,每天自动检查内存,超了发邮件/短信提醒:

sql 复制代码
-- 简单的内存告警检查脚本
DECLARE @UsedMB INT;
SELECT @UsedMB = (physical_memory_in_use_kb/1024) FROM sys.dm_os_process_memory;

IF @UsedMB > 40000  -- 阈值,根据你机器配置调整
BEGIN
    -- 这里可以调用存储过程发送邮件通知
    PRINT '警告:SQL Server内存占用已超过阈值!当前使用:' + CAST(@UsedMB AS VARCHAR) + ' MB';
END;

💡 核心思路 :SQL Server吃内存是为了。只要不导致服务器卡顿、不报错,高内存利用率反而是服务器配置在物尽其用。