前言
近期不少朋友反馈,数据库服务器内存爆满,让人头疼。下面就来拆解一下应急处理和长期优化的思路。

SQL Server数据库服务器内存占用高,其实是个普遍现象。不用一看到内存飙上去就慌,因为绝大多数数据库为了跑得更快,都会把一部分数据缓存到内存里。只要服务器还有空闲内存,通常不用过度紧张。当然,如果内存频繁爆满,导致服务器异常甚至宕机,那就另当别论了。
一、 立刻处理(快速释放、恢复)
清除缓存(谨慎使用,仅在紧急时)
这条命令专门用来清空缓存,紧急情况下可以临时救急。但要注意,清空缓存可能导致瞬间性能波动,所以建议在业务低峰期操作。
DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; 杀掉阻塞/耗时查询
先找出那些吃资源的会话,然后手动“干掉”。
-- 查看耗时且占用高的会话(限制大于50是因为2005之前系统会话ID都小于等于50)SELECT session_id, status, command, wait_type FROM sys.dm_exec_requests WHERE session_id > 50;-- 杀掉会话(替换 SPID)。注意不要误杀,有些是系统会话(比如写日志、清理)KILL 56;
二、 根源排查
确认内存使用情况
-- 查看数据库内存使用 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, (a vailable_physical_memory_kb / 1024) AS A vailable_OS_Memory_MB, system_memory_state_desc FROM sys.dm_os_sys_memory;
结论:如果A vailable_OS_Memory_MB还比较充裕,那说明只是SQL Server占满了自己的缓冲池,属于正常现象;如果可用内存极少,甚至服务器Swap分区都爆满了,那才需要紧急优化。
这里有一个常见误区:不要直接用任务管理器去看SQL Server的内存占用,它显示的值往往不准确。原因在于,如果SQL Server启用了“锁定内存页”权限,大部分内存分配会通过AWE API进行,这部分内存在任务管理器的“进程私有字节”中根本看不到。用上面的DMV查询,才能拿到真实数据。
定位是谁在“吃内存”
-- 按数据库统计内存占用SELECT DB_NAME(database_id) AS DatabaseName, COUNT(*) * 8/1024 AS CacheSize_MBFROM sys.dm_os_buffer_descriptorsGROUP BY DB_NAME(database_id)ORDER BY CacheSize_MB DESC;GO
三、 永久优化方案(稳定运行)
配置最大内存(关键!)
这是很多人都忽略的一步,但恰恰是最关键的设置。如果不限制SQL Server的内存使用上限,它可能会把系统内存吃光,导致Windows或者其他服务挂掉。
sp_configure 'show advanced options', 1; RECONFIGURE;sp_configure 'max server memory (MB)', 32768; -- 假设机器64G,留32G给系统和其他程序RECONFIGURE;
索引与查询优化
内存占用高,背后多半是查询写得不好——比如全表扫描、索引缺失、滥用函数、或者一次性查询大量大字段数据。
-- 检查碎片DBCC SHOWCONTIG ('表名');-- 重组(碎片<30%)或重建(碎片>30%)ALTER INDEX ALL ON 表名 REBUILD;重建/重组索引:碎片超过30%就重建,低于30%重组即可。
清理执行计划缓存:用于解决参数嗅探问题。
DBCC FREEPROCCACHE;
四、 监控预警建议
建议在服务器上建一个作业,每天自动检查内存使用量,一旦超标就发送邮件或信息提醒。
-- 简单的内存告警检查脚本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吃内存,本质上是为了更快。只要不导致服务器卡顿、不报错、系统稳定运行,内存利用率高反而是服务器资源物尽其用的表现。
