临时数据库(TempDb)
在今天的 性能调优培训 里我们讨论下TempDb——SQL Server的公共厕所,在SQL Server里我是这样描述它的。我们的每个人都会经常使用TempDb。有些人直接使用它,有些人不直接使用它。今天我想给你概括介绍下SQL Server里TempDb的用法,另外我会给你为了更好的性能,如何配置TempDb的一些最佳实践。
TempDb用法
我们的每个人使用TempDb。这是我们要接受的事实。因此按需配置TempDb非常重要——即为了获得良好的性能。TempDb存储下列2类对象:
- 用户对象( User Objects )
- 内部对象( Internal Objects )
- 版本存储( Version Store )
我们来详细看下这些对象。当我们讨论用户对象时,我们指的是临时表,表变量和表值函数。在SQL Server里临时表有2种:本地临时表,全局临时表。本地临时表使用“#”前缀创建,只局限于创建它的会话。一旦你关闭你的会话,本地临时表也会在 TempDb里消失。本地临时表的好处:使用它们,你可以克服锁和阻塞问题,因为每个会话都拥有它自己的,专用的临时表。
在SQL Server里还有全局临时表,它用“##”前缀创建。这些临时表在所有会话里都可以访问,因为它是全局创建的。最后,SQL Server为你提供表变量,它在TempDb里也是物理持久的,但局限于你定义表变量的批处理里。表变量是SQL Server里的内存中结构是个误解。它们在TempDb里总是持久的。从表值函数返回的表在TempDb里也是持久的。因此当在SQL Server里使用这些对象,按需配置它们非常重要。
包括作为开发人员或DBA的你在内——SQL Server本身也总为内部创建对象存储使用TempDb。当你使用 DBCC CHECKDB 或 DBCC CHECKTABLE 运行一致性检查时,SQL Server在TempDb里分配工作表,执行计划里的排序或者哈希操作也会蔓延到TempDb,这些在TempDb里也都是物理持久的。当你使用游标时,甚至Service Broker,你在消耗TempDb里的空间。如果你用 SORT_IN_TEMPDB 选项重建索引,你也在使用TempDb。在SQL Server里TempDb在每个地方都会用到。
另外对于内部对象,SQL Server也支持所谓的版本存储(Version Store),在SQL Server里当你使用乐观并发控制(optimistic concurrency)时或进行在线索引操作时会用到。内部SQL Server分版本存储为2个不同的存储:对于触发器(triggers),快照隔离(Snapshot Isolation),提交读快照隔离(Read Committed Snapshot Isolation),还有多数据结果集(Multiple Active Result Sets (MARS)),使用 通用版本存储(Common Version Store) 。在SQL Server里 在线索引重建版本存储(Online Index Rebuild Version Store) 被在线索引操作使用。
TempDB配置
在默认配置里运行TempDb并真是个好想法。TempDb的默认配置只给你一个数据文件和一个事务日志文件。在SQL Server 2014里,数据文件初始大小有8M,对于事务日志是1M。2个文件都设置为10%的自动增长。这个配置会带来几个问题:
- 太多超时的自动增长操作
- 日志文件碎片
- 闩锁竞争(Latch contention)
我们来详细看下这些问题。使用默认的8M的初始大小,你的TempDb使用昂贵的自动增长操作会有超时增长。如果你知道你的TempDb在大小上需要一定的MB,你需要把它设置为初始大小,因为在SQL Server启动期间,TempDb总从model数据里重新创建。那个方式你可以避免自动增长操作。如果你依赖于自动增长设置,你也应该使用固定大小,而不是百分比值。这也允许你估计自动增长操作需要花费的时间。使用百分比值,基于当前你的文件大小会花费越来越长的时间。
你也需要仔细TempDd的事务日志的大小,因为那里自动增长操作是非常昂贵的。对于任何事务日志, SQL Server不能使用 即时文件初始化(Instant File Initialization) 。这意味着在事务日志的自动增长期间,你的数据库不能访问事务。对于性能关键系统,在事务日志上的自动增长操作基本是不可行的。
最后你也会碰到TempDb里的闩锁竞争问题,因为只有一个数据文件可用。当SQL Server在TempDb里分配新对象时,SQL Server需要读取特定页(SGAM,GAM,PFS)。这些页在去写期间必须被竞争。当你运行高度依赖于TempDB的工作时,在TempDb里这些热页上会有竞争问题。
这个问题的解决方法是对于TempDb使用多个数据文件,因为那时SQL Server会通过多个数据文件使用循环分配算法(Round-Robin allocation algorithm),它会减少闩锁竞争问题。如果你使用多个数据文件,你也需要确保初始大小(一个可能的自动增长值)设置为一样的值,这样的话它们会同时增长。