tempdb文件写远远大于读,内存不断飙升问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tempdb文件写远远大于读,内存不断飙升问题相关的知识,希望对你有一定的参考价值。

  最近忽然碰到了一台数据库服务器磁盘IO升高一倍多,内存增长很快。cpu正常,网络流量正常,明显不是有人在拉数据。就想着分析看看。最终找到了原因。记录下分析过程。

1、用dbcc showfilestats  查看文件空间分配情况;用sp_lock和sp_who查看是否有死锁情况。

2、用select * from tempdb..sysobjects where xtype=‘U‘ 查看tempdb里有哪些对象。带1个#的表是无法查看表数据的,带##的是全局临时表是可以查看表数据的。

3、运行下面的脚本得到逻辑写次数比较多的sql语句。

SELECT TOP 1000 
       ST.text AS ‘执行的SQL语句‘,
       QS.execution_count AS ‘执行次数‘,
       QS.total_elapsed_time AS ‘耗时‘,
       QS.total_logical_reads AS ‘逻辑读取次数‘,
       QS.total_logical_writes AS ‘逻辑写入次数‘,
       QS.total_physical_reads AS ‘物理读取次数‘,       
       QS.creation_time AS ‘执行时间‘ ,  
       QS.*
FROM   sys.dm_exec_query_stats QS
       CROSS APPLY 
sys.dm_exec_sql_text(QS.sql_handle) ST
WHERE  QS.creation_time BETWEEN ‘2017-01-19 00:00:00‘ AND ‘2017-01-19 14:00:00‘ 
ORDER BY
     QS.total_logical_writes DESC 

4、另外这里有微软官方关于这个问题的解决文档:

技术分享https://blogs.msdn.microsoft.com/apgcdsd/2011/01/24/tempdb/
技术分享https://blogs.msdn.microsoft.com/apgcdsd/2011/02/10/sql-servertempdb/ 
 
从微软官方获取一下运行脚本:

use tempdb

--— 每隔1秒钟运行一次,直到用户手工终止脚本运行

while 1=1

begin

select getdate()

--— 从文件级看tempdb使用情况

dbcc showfilestats

--— Query 1

--— 返回所有做过空间申请的session信息

Select ‘Tempdb‘ as DB, getdate() as
Time,


SUM (user_object_reserved_page_count)*8 as user_objects_kb,


SUM (internal_object_reserved_page_count)*8 as internal_objects_kb,


SUM (version_store_reserved_page_count)*8 as version_store_kb,


SUM (unallocated_extent_page_count)*8 as freespace_kb

From sys.dm_db_file_space_usage

Where database_id = 2

--— Query 2

--— 这个管理视图能够反映当时tempdb空间的总体分配

SELECT t1.session_id,

t1.internal_objects_alloc_page_count, t1.user_objects_alloc_page_count,

t1.internal_objects_dealloc_page_count ,
t1.user_objects_dealloc_page_count,

t3.*

from sys.dm_db_session_space_usage t1 ,

--— 反映每个session累计空间申请

sys.dm_exec_sessions as t3

--— 每个session的信息

where

t1.session_id = t3.session_id

and
(t1.internal_objects_alloc_page_count>0

or t1.user_objects_alloc_page_count
>0

or
t1.internal_objects_dealloc_page_count>0

or
t1.user_objects_dealloc_page_count>0)

--— Query 3

--— 返回正在运行并且做过空间申请的session正在运行的语句

SELECT t1.session_id,

st.text

from sys.dm_db_session_space_usage as
t1,

sys.dm_exec_requests as t4

CROSS APPLY
sys.dm_exec_sql_text(t4.sql_handle) AS st

where t1.session_id = t4.session_id

and
t1.session_id =244

and
(t1.internal_objects_alloc_page_count>0

or t1.user_objects_alloc_page_count
>0

or
t1.internal_objects_dealloc_page_count>0

or
t1.user_objects_dealloc_page_count>0)

waitfor delay ‘0:1:0‘

end

 

5、通过下面的sql语句找到是哪个数据库占用的内存比较大。

select count(*)*8/1024 as ‘cachesize(MB)‘,
db_name(database_id) ‘database‘
from sys.dm_os_buffer_descriptors
group by db_name(database_id),database_id
order by ‘cachesize(MB)‘ desc

6、通过以上语句的运行及仔细分析,最终找到是有一个功能需要随机显示十条数据,结果被写成了每次从数据库里通过n张表的join取出1000条数据并把每列通过case when转换后返回,程序在这1000条返回的数据里挑选十条数据显示。只要用户刷新几次,这个sql的效率就测出来了。

7、第一次碰到这种问题,记录下来,以便参考。很多时候貌似什么都会(委托、多线程、泛型),但是忽略了这些基本的性能,sql随便乱写,最终只会导致写出来的功能经不起时间和网站流量的考验,功能回炉改造是唯一出路。

 

 

 

以上是关于tempdb文件写远远大于读,内存不断飙升问题的主要内容,如果未能解决你的问题,请参考以下文章

ReadWriteLock 读写锁(读书笔记)

数据库读写分离,主从同步实现方法

Mysql缓存方案

java内存映射文件多线程读/写

从 MMU 看内存管理

从 MMU 看内存管理