1. 问题发现
在学习内存调优时,使用如下代码,查询目前内存缓冲区中生产数据库的每个对象缓存页计数
SELECT count(*)AS cached_pages_count ,name ,index_id FROM sys.dm_os_buffer_descriptors AS bd INNER JOIN ( SELECT object_name(object_id) AS name ,index_id ,allocation_unit_id FROM sys.allocation_units AS au INNER JOIN sys.partitions AS p ON au.container_id = p.hobt_id AND (au.type = 1 OR au.type = 3) UNION ALL SELECT object_name(object_id) AS name ,index_id, allocation_unit_id FROM sys.allocation_units AS au INNER JOIN sys.partitions AS p ON au.container_id = p.partition_id AND au.type = 2 ) AS obj ON bd.allocation_unit_id = obj.allocation_unit_id WHERE database_id = db_id() GROUP BY name, index_id ORDER BY cached_pages_count DESC;
发现前段应用程序已经不再使用的表,数据页缓存数排在首位,而且页数非常之多。这张表是之前用来作为数据统计分析的计算报表,后来上了数据仓库以及BI系统后,这张表就废弃掉了。但为什么内存中还是缓存这么多数据页?现在系统的内存并非是足够大,大到可以缓存整个数据库的数据页面,所以,感觉这些不再使用的数据页面应该被置换出内存
2.问题分析
为了验证这种表的使用情况,使用如下语句查询表的索引使用情况
SELECT * FROM sys.dm_db_index_usage_stats ddius WHERE ddius.object_id = OBJECT_ID('t_rpt_office_shop_data')
发现索引的user_scan 等确实为0,代表自上次服务启动以来,应用程序没用提交过对这个表的查询。
但发现system_scan不为0,而且last_system_scan的日期为凌晨。
所以猜想是不是凌晨的数据库维护计划中有导致system_scan的操作
继续查看维护计划,发现果真有一个任务--更新统计信息任务,而且扫描类型是完全扫描
3.问题原因
所以,问题是由每天早上的更新统计信息任务造成,因为执行完全扫描,相当于每天凌晨对这个表执行了一次全表扫描,此时会将数据页加载到内存缓冲区中。而且我发现凌晨这段时间内存的页面生命周期基本接近为0,估计也是这个造成的。
4.问题处理
以下是我的处理方式,大家指正下~
- 将维护计划中的更新统计信息步骤删除掉,第二天发现内存缓冲的对象数据页计数基本和预测一致。
- 将不在使用的表进行数据压缩,减少磁盘空间的占用