9.3 Tempdb的并发阻塞

在介绍Tempdb的并发问题前,先介绍几个比较特殊的数据页。

PFS(Page Free Space),用于标识数据页空间的使用情况,以字节标识,可以表示数据页使用百分比,例如使用百分五十,百分八十,百分九十五以及完全被使用,同时,还有一个字节位表示数据页的类型,例如IAM页等。一个PFS页,可以标识64MB的数据页空间使用情况。

GAM(Global Allocation Map),用于标识数据盘区(Extent)是否已分配,以位标识,当位为0时,表示盘区还未分配,当位为1时,表示盘区已经分配。一个GAM页可以标识大约4GB的数文件空间标识。

SGAM(Shared Global Allocation Map),用于标识混合数据盘区是否已分配,以位标识。混合空间中可能被存储数据,也可能存储索引。一个SGAM页可以标识大约4GB的数据文件混空间标识。

Tempdb中,临时表的数据特性如前面章节中介绍的,当会话中创建临时表并初始化时,分配数据空间,在会话中删除临时表,或会话结束,便会将空间回收。数据的新增和删除,都需要使用到数据页,当数据页的存储空间大小发生变化时,PFS的字节标识值就需要发生变化。当这样的操作频率地发生在相同的一块数据页空间区域内时。如前面讲闩锁时所知道的,内在页在更新时,是需要使用闩锁来实现互斥的,当并发操作累积到特定的数值时,将会频繁地出现闩锁等待,此时有可能会造成服务器CPU使用率上升,甚至发生CPU满负荷的情况。

出于这样的原因,通常建议将Tempdb的数据文件个数增加到与逻辑CPU个数相同。这样可以达到数据分流的目的,避免在相同的数据区域内频繁地擦写数据。

相同的情况也有可能发生在GAM和SGAM页上,只是GAM和SGAM要求临时表的数据量较大。

除了PFS,GAM以及SGAM几个root页的并发阻塞问题外,Tempdb还可能因为频繁地创建临时表而发生系统表阻塞的问题。例如,在高并发访问的某个存储过程中,使用SELECT INTO的方式创建临时表,当并发访问足够高,或者查询语句需要消耗的时间比较长且有一定的并发量时,可能导致系统的元数据表,比如sys.objects视图对应的系统元数据表sysschobjs或者sys.columns视图对应的这些系统元数据表syscolpars,这些系统元数据也有可能由于高并发以及较长的事务而产生大量的系统阻塞的情况。解决这样问题的方式便是,创建临时表时,不应该将创建临时表的语句包含在较长的事务当中。避免Tempdb的系统表被锁住,引起别的进程无法正常创建或操作临时表。

另外,在更高并发的情况下,为了达到Tempdb有更好的数据吞吐能力,建议将数据文件放在不同的磁盘上,以提高磁盘的吞吐量。

接下来,我们会使用到一个测试工具,工具名为ostress。是微软提供的SQL Server测试工具组件RML Utilities For SQL Server中的一个,大家可以到微软官网下载该工具,这个工具组件是免费的。

Tempdb并发示例

以下链接为64位工具下载地址:

http://www.microsoft.com/en-us/download/details.aspx?id=4511

以下是32位工具的下载地址:

http://www.microsoft.com/en-us/download/details.aspx?id=8161

下载完测试软件,并安装后,我们需要在数据库中,创建相应的存储过程,存储过程代码如代码清单9-5中所示,创建两个存储过程,usp_temp_table_test作为子存储过程,usp_loop_test_table_test循环调用它。

CREATE PROC dbo.usp_temp_table_test

AS

BEGIN

    CREATE TABLE #table(c1 INT,c2 CHAR(5000));

    DECLARE @i INT=1;

    WHILE(@i<=10)

    BEGIN

        INSERT INTO #table (c1,c2)VALUES (@i,'test');

        SET @i+=1;

    END

END

GO

 

CREATE PROC dbo.usp_loop_temp_table_test

AS

BEGIN

    SET NOCOUNT ON;

    DECLARE @i INT=1;

    WHILE(@i<100)

    BEGIN

        EXEC dbo.usp_temp_table_test;

        SET @i+=1;

    END

END

GO

代码清单9-5 Tempdb并发阻塞测试

创建对应的代码后,使用ostress模拟用户并发的情况,执行下面的Windows批处理指令,如代码清单9-6中所示,使用ostress模拟300个并发执行我们创建的存储过程。

"C:\Program Files\Microsoft Corporation\RMLUtils\ostress.exe" -S(local)\SQL2012 -E -Q"exec [AdvantureWorks2008R2].dbo.usp_loop_temp_table_test;" -o"D:\output.txt" -n300

代码清单9-6 执行ostress工具

在执行ostress时,使用动态管理视图查看当前服务器内存中,Tempdb内存页的闩锁等待情况,全县下面的语句,查询动态管理视图sys.dm_os_waiting_tasks获取相应的阻塞信息,代码如代码清单9-7中所示。

;WITH waiting_tasks

AS (SELECT session_id,

                     wait_type,

                     wait_duration_ms,

                     blocking_session_id,

                     resource_description,

PageID = CONVERT(INT,RIGHT(resource_description,LEN(resource_description)-CHARINDEX(':',resource_description,3)))

FROM sys.dm_os_waiting_tasks

WHERE wait_type LIKE 'PAGE%LATCH_%' AND resource_description LIKE '2:%')

SELECT session_id,

     wait_type,

     wait_duration_ms,

     blocking_session_id,

     resource_description,

ResourceType = CASE WHEN PageID=1 OR PageID%8088=0 THEN 'PFS Page'

WHEN PageID=2 OR PageID%511232=0 THEN 'GAM Page'

WHEN PageID=3 OR (PageID-1)%511232=0 THEN 'SGAM Page'

ELSE 'Not PFS, GAM, or SGAM page'

END

FROM waiting_tasks;

代码清单9-7 查看当前tempdb的Latch情况

通过查询语句,可以看到如图9-5中所示,此时服务器绝大部分是PFS数据页的闩锁等待。

图9-5 服务器的闩锁等待

从执行结果上看到,300个并发任务中,有297个正在等待数据页2:1:1,此处页为PFS数据页,其等待类型为PAGELATCH_UP类型。导致这样的原因这是因为Tempdb在实例中只有一个数据文件,高并发的情况下,导致数据页并发更新带来的阻塞。

9.3.1 配置Tempdb

如何配置Tempdb可以避免图9-5中的问题,在前面小节中我们已经有提到过了,提高并发的方法便是增加数据文件,将并发分开,避免对同一个文件进行操作。那么配置多个文件需要注意些什么事项呢?

SQL Server对于具有多个文件的数据库在写入数据时,数据库引擎将按照各个数据文件的大小比例进行数据分配,因此,当对Tempdb配置多个文件时,要保持Tempdb的数据文件大小保持一致,这样才能达到在存储Tempdb数据时,可以达到近乎平均使用和分配数据文件的作用,才能达到平均使用每个文件中的PFS,GAM以及SGAM这些root数据页的目的。

Tempdb的并发阻塞的更多相关文章

  1. 深入浅出 Java Concurrency (25): 并发容器 part 10 双向并发阻塞队列 BlockingDeque[转]

    这个小节介绍Queue的最后一个工具,也是最强大的一个工具.从名称上就可以看到此工具的特点:双向并发阻塞队列.所谓双向是指可以从队列的头和尾同时操作,并发只是线程安全的实现,阻塞允许在入队出队不满足条 ...

  2. thinkphp并发 阻塞模式与非阻塞模式

    结构代码 public function index(){ $fp = fopen("lock.txt", "w+"); if(flock($fp,LOCK_E ...

  3. Java并发--阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  4. java并发阻塞队列

    Java 并发编程利用 Condition 来实现阻塞队列 You are here:  开发&语言 - Java 文章 发布于 2017年06月26日  阅读 944 并发编程   什么是阻 ...

  5. MySQL Online DDL与DML并发阻塞关系总结

    MySQL DDL操作执行的三种方式 1,INPLACE,在进行DDL操作时,不影响表的读&写,可以正常执行表上的DML操作,避免与COPY方法相关的磁盘I/O和CPU周期,从而最小化数据库的 ...

  6. Redis实现并发阻塞锁方案

    由于用户同时访问线上的下订单接口,导致在扣减库存时出现了异常,这是一个很典型的并发问题,本篇文章为解决并发问题而生,采用的技术为Redis锁机制+多线程的阻塞唤醒方法. 在实现Redis锁机制之前,我 ...

  7. Expert 诊断优化系列------------------给TempDB 降温

    前面文章针对CPU.内存.磁盘.语句.等待讲述了SQL SERVER的一些基本的问题诊断与调优方式.为了方便阅读给出导读文章链接方便阅读: SQL SERVER全面优化-------Expert fo ...

  8. 高并发第十三弹:J.U.C 队列 SynchronousQueue.ArrayBlockingQueue.LinkedBlockingQueue.LinkedTransferQueue

    因为下一节会说线程池,要用线程池 那么线程池有个很重要的参数 就是Queue的选择 常用的队列其实就两种: 先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能.从某种程度上来说这种 ...

  9. JUC——并发集合类

    如果要进行多个数据的保存,无疑首选类集(List.Set.Queue.Map),在类集的学习的时候也知道一个概念:许多集合的子类都具有同步与异步的差别,但是如果真的要在多线程之中去使用这些类,是否真的 ...

随机推荐

  1. Scala 深入浅出实战经典 第43讲:主要介绍类型变量bound

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  2. web项目总结

    web项目 Webroot下面的index.jsp页面的内容: <%@ page language="java" pageEncoding="UTF-8" ...

  3. Linux之crontab

    一  cron crond位于/etc/rc.d/init.d/crond 或 /etc/init.d 或 /etc/rc.d /rc5.d/S90crond,最总引用/var/lock/subsys ...

  4. Django 源码小剖: 初探中间件(middleware)

    因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddleware 就已经默认安装.  BaseH ...

  5. Akismet API 密钥(key)免费获取方法

    Akismet插件是用户使用最广泛的垃圾评论插件,也是wordpress的创始人制作的,同时它也毫无疑问的成为wordpress的默认安装插件,这样的插件可以帮助用户解决垃圾评论的烦恼,而且也不用访客 ...

  6. 微信中直接下载APK

    某天在微信中偶遇一个二维码,识别二维码竟然可以直接下载APK! 该二维码如下: 解码后获得地址:(在线解码工具) http://www.rmdown.com/newt66y.apk 这不就是个普通的A ...

  7. Android上面安装Linux的方法

    方法一: 并行安装Linux(不在Android操作系统之上运行,需要设备已经unlocked并且rooted) 我还没玩过.放两个书签: How to Install Ubuntu on Andro ...

  8. Equals Finalize GetHashCode GetType MemberwiseClone ReferenceEquals ToString String.IsInterned

    参考资料: http://blog.csdn.net/afgasdg/article/details/6889383 http://www.cnblogs.com/skyivben/archive/2 ...

  9. 修改CMD的编码

    修改CMD的编码   使用chcp命令,格式为chcp [nnn]后面3位数字为codepage number.简体中文为936UTF8 为 65001United States 为 437

  10. DNS反射攻击阻止

    刚搭的dns server就有贱人跑dns反射放大攻击,据说bind高版本没洞,但是日志刷刷的跑,感觉也不放心,而且毕竟dns是返回了请求的,所以找了点资料备忘 先设定不受限制的网段 iptables ...