SQLSERVER Tempdb的作用及优化
tempdb 系统数据库是可供连接到 SQL Server 实例的所有用户使用的全局资源。tempdb 数据库用于存储下列对象:用户对象、内部对象和版本存储区。
用户对象
用户对象由用户显式创建。这些对象可以位于用户会话的作用域中,也可位于创建对象所用例程的作用域中。例程可以是存储过程、触发器或用户定义函数。用户对象可以是下列项之一:
-
用户定义的表和索引
-
系统表和索引
-
全局临时表和索引
-
局部临时表和索引
-
table 变量
-
表值函数中返回的表
内部对象
内部对象是根据需要由 SQL Server 数据库引擎创建的,用于处理 SQL Server 语句。内部对象可以在语句的作用域中创建和删除。内部对象可以是下列项之一:
-
用于游标或假脱机操作以及临时大型对象 (LOB) 存储的工作表。
-
用于哈希联接或哈希聚合操作的工作文件。
-
用于创建或重新生成索引等操作(如果指定了 SORT_IN_TEMPDB)的中间排序结果,或者某些 GROUP BY、ORDER BY 或 UNION 查询的中间排序结果。
每个内部对象至少使用九页;一个 IAM 页,一个八页的区。有关页和区的详细信息,请参阅页和区。
下表列出了 SQL Server 中创建 tempdb 的用户对象、内部对象或行版本的功能。只要有可能,便会提供估计磁盘空间使用量的方法。
功能 |
tempdb 使用 |
其他信息 |
---|---|---|
启用了触发器的大容量加载操作 |
启用触发器后便可使用大容量导入优化。SQL Server 将针对更新或删除事务的触发器使用行版本控制。每个删除或更新的行的副本都会添加到版本存储区中。请参阅此表后面部分中的“触发器”。 |
|
公用表表达式查询 |
公用表表达式可以认为是在单个 SELECT、INSERT、UPDATE、DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集。 当公用表表达式查询的查询计划使用 Spool 运算符保存中间查询结果时,数据库引擎会在 tempdb 中创建工作表以支持此操作。 |
|
游标 |
键集驱动游标和静态游标使用在 tempdb 中生成的工作表。键集驱动游标使用工作表来存储标识游标中各行的键集。静态游标使用工作表来存储游标的完整结果集。 如果选择的查询计划不同,则游标的磁盘空间使用量也可能会不同。如果查询计划与早期版本 SQL Server 中的查询计划相同,则磁盘空间使用量也大致相同。 |
|
数据库邮件 |
请参阅此表后面部分中的“Service Broker”。 |
|
DBCC CHECKDB |
DBCC CHECKDB 使用 tempdb 工作表来保存中间结果或进行排序操作。 若要确定操作的 tempdb 磁盘空间要求,请运行 DBCC CHECKDB WITH ESTIMATEONLY。 |
|
事件通知 |
请参阅此表后面部分中的“Service Broker”。 |
|
索引 |
当创建或重新生成索引(脱机或联机)并将 SORT_IN_TEMPDB 选项设置为 ON 时,可以引导数据库引擎使用 tempdb 来存储用于生成索引的中间排序结果。如果指定了 SORT_IN_TEMPDB 并需要进行排序,则 tempdb必须具有足以包含最大索引的磁盘空间,另外还必须具有大小等于 index create memory 选项的值的磁盘空间。有关详细信息,请参阅索引磁盘空间示例。 表和索引可以进行分区。对于已分区索引,如果指定了 SORT_IN_TEMPDB 索引选项并且索引与基表对齐,则 tempdb 中具有的空间必须足以容纳最大分区的中间排序段。如果索引未对齐,则 tempdb 中具有的空间必须足以容纳所有分区的中间排序段。有关详细信息,请参阅已分区索引的特殊指导原则。 联机索引操作使用行版本控制来使索引操作不受其他事务所做的修改的影响。行版本控制不需要对已读取的行请求共享锁。在联机索引操作期间,并发的用户更新和删除操作需要一定的空间以用于 tempdb 中的版本记录。如果联机索引操作使用 SORT_IN_TEMPDB 并需要进行排序时,则 tempdb 除了具有用于先前所述的中间排序结果的磁盘空间之外,还必须具有额外的磁盘空间。创建、删除或重新生成聚集索引的联机索引操作也需要额外的磁盘空间来生成并维护临时映射索引。CREATE 和 UPDATE STATISTICS 操作可以使用 tempdb 来将行样本排序以便生成统计信息。有关详细信息,请参阅索引 DDL 操作的磁盘空间要求。 |
|
大型对象 (LOB) 数据类型变量和参数 |
大型对象数据类型包括 varchar(max)、nvarchar(max)、varbinary(max)、text、ntext、image 和 xml。这些类型的最大大小可达 2 GB,并可在存储过程、用户定义函数、批处理或查询中用作变量或参数。定义为 LOB 数据类型的参数和变量在值很小的情况下将使用主内存作为存储区。但是,较大值将存储在 tempdb 中。当 LOB 变量和参数存储在 tempdb 中时,可以将它们视为内部对象。您可以查询 sys.dm_db_session_space_usage 动态管理视图,以报告针对给定会话分配给内部对象的页。 有些内部字符串函数(例如,SUBSTRING 或 REPLICATE)在针对 LOB 值执行操作时,可能需要在 tempdb 中进行中间临时存储。同样,如果对数据库启用了基于行版本控制的事务隔离级别并且对大型对象进行了修改,则 LOB 的已更改片段将被复制到 tempdb 的版本存储区中。 |
|
多个活动的结果集 (MARS) |
单个连接下可以出现多个活动结果集,这通常称为 MARS。如果 MARS 会话在存在活动结果集的情况下发出数据修改语句(例如 INSERT、UPDATE 或 DELETE),则将受到修改语句影响的行存储在 tempdb 的版本存储区中。请参阅此表后面部分中的“行版本控制”。 |
|
查询通知 |
请参阅此表后面部分中的“Service Broker”。 |
|
查询 |
包含 SELECT、INSERT、UPDATE 和 DELETE 语句的查询可以使用内部对象来存储哈希联接、哈希聚合或排序的中间结果。 缓存查询执行计划时,也会缓存计划所需的工作表。缓存工作表时,该表会截断,并且缓存中保留九页以便重用。这样可提高下次执行查询时的性能。如果系统内存不足,则数据库引擎可以删除执行计划以及关联的工作表。 |
|
行版本控制 |
行版本控制是用于支持下列功能的常规框架:
行版本在活动事务必须对其进行访问时一直保存在 tempdb 版本存储区中。当前版本存储区的内容在 sys.dm_tran_version_store 中返回。由于版本存储区页是全局资源,所以在文件级别对其进行跟踪。您可以使用 sys.dm_db_file_space_usage 中的 version_store_reserved_page_count 列来查看版本存储区的当前大小。版本存储区清除必须考虑需要访问特定版本的运行时间最长的事务。可通过查看 sys.dm_tran_active_snapshot_database_transactions 中的 elapsed_time_seconds 列来发现与版本存储区清除相关的运行时间最长的事务。可以使用 Transactions 对象中的 Free Space in Tempdb (KB) 和 Version Store Size (KB) 计数器来监视 tempdb 中行版本存储区的大小和增长速率。有关详细信息,请参阅 SQL Server Transactions 对象。 若要估计 tempdb 中行版本控制所需的空间量,请务必先考虑活动事务必须将其所有更改保留在版本存储区中。这意味着稍后启动的快照事务可以访问旧版本。此外,如果存在活动的快照事务,则由快照启动时处于活动状态的事务生成的所有版本存储区数据也必须保留。 下面是基本公式: [Size of Version Store] = 2 * [Version store data generated per minute] * [Longest running time (minutes) of your transaction] |
|
Service Broker |
Service Broker 可帮助开发人员构建异步的松散耦合应用程序,在这些应用程序中彼此独立的组件相互配合来完成一项任务。这些应用程序组件将交换包含完成任务所需的信息的消息。Service Broker 显式使用 tempdb 来保留内存中无法保留的现有对话框上下文。每个对话框的大小大约为 1 KB。 此外,Service Broker 将隐式使用 tempdb 在查询执行上下文中缓存对象(例如,用于计时器事件和后台传递会话的工作表)。 |
|
存储过程 |
存储过程可以创建用户对象,例如全局临时表或局部临时表及其索引、变量或参数。可以缓存存储过程中的临时对象以优化删除和创建这些对象的操作。这一行为会增加 tempdb 磁盘空间要求。每个临时对象可最多存储九页以便重用。请参阅此表后面部分中的“临时表和 table 变量”。 |
创建存储过程(数据库引擎) |
临时表和 table 变量
|
临时表和 table 变量存储在 tempdb 中。临时表对象的磁盘空间要求与早期版本的 SQL Server 中的要求相同。估计临时表大小的方法与估计标准表大小的方法相同。有关详细信息,请参阅估计表的大小。 table 变量的行为类似于局部变量。table 变量的类型为 table,主要用于临时存储作为表值函数结果集返回的行集。保存 table 变量所需的磁盘空间取决于声明变量以及变量中存储的值的大小。 当满足下列条件时会缓存本地临时表和变量:
缓存临时表或 table 变量时,在临时对象完成使命时没有将其删除。相反,临时对象将截断。临时对象可最多存储九页,以便在下次执行调用时重用。通过缓存,删除和创建对象的操作可以非常快速地执行,并可减少页分配争用。 为了获得最佳性能,应该使用以下公式计算 tempdb 中的缓存本地临时表或 table 变量所需的磁盘空间: 9 page per temp table * number of average temp tables per procedure * number of maximum simultaneous executions of the procedure |
|
触发器 |
在 tempdb 中创建 AFTER 触发器中使用的 inserted 和 deleted 表。即,由触发器更新或删除的行应进行版本控制。这包括由触发触发器的语句修改的所有行。由触发器插入的行不进行版本控制。 INSTEAD OF 触发器使用 tempdb 的方式类似于查询所使用的方式。INSTEAD OF 触发器的磁盘空间使用量与早期版本的 SQL Server 中的使用量相同。请参阅此表前面部分中的“查询”。 当您在启用触发器的情况下大容量加载数据时,将向版本存储区添加每一删除行或更新行的一份副本。 |
|
用户定义函数 |
用户定义函数可以创建临时用户对象,例如全局临时表或局部临时表及其索引、变量或参数。例如,表值函数的返回表存储在 tempdb 中。 允许对标量函数和表值函数中的参数和返回值使用的数据类型包括大多数 LOB 数据类型。例如,返回值的类型可以为 xml 或 varchar(max)。请参阅此表前面部分中的“大型对象 (LOB) 数据类型变量和参数”。 可以缓存用户定义表值函数中的临时对象以优化删除和创建这些对象的操作。请参阅此表前面部分中的“临时表和 table 变量”。 |
|
XML |
类型为 xml 的变量和参数最大大小可达 2 GB。只要值比较小,它们便会使用主内存作为存储区。但是,较大值将存储在 tempdb 中。请参阅此表前面部分中的“大型对象 (LOB) 数据类型变量和参数”。 sp_xml_preparedocument 系统存储过程会在 tempdb 中创建一个工作表。MSXML 分析器使用该工作表来存储已分析的 XML 文档。执行存储过程时,tempdb 的磁盘空间要求几乎与指定的 XML 文档的大小成正比。 |
确定 tempdb 在生产环境中的适当大小取决于多种因素。如本主题中前面所述,这些因素包括现有工作负荷以及使用的 SQL Server 功能。建议您通过在 SQL Server 测试环境中执行下列任务来分析现有的工作负荷:
-
设置 tempdb 的自动增长。
-
执行单独的查询或工作负荷跟踪文件,监视 tempdb 空间使用。
-
执行索引维护操作(例如,重新生成索引),监视 tempdb 空间。
-
使用前面步骤中的空间使用值来预测总的工作负荷使用情况;针对计划的并发活动调整此值,然后相应地设置 tempdb 的大小。
优化 tempdb 性能
tempdb 数据库的大小和物理位置可能会影响系统的性能。例如,如果为 tempdb 定义的大小过小,则每次重新启动 SQL Server 实例时,都可能会占用部分系统处理负荷,以使 tempdb 自动增长到支持工作负荷所需的大小。您可以通过增加 tempdb 数据和日志文件的大小来避免此开销。有关确定 tempdb 所需的适当磁盘空间量的信息
-
将文件增量设置为合理的大小以避免 tempdb 数据库文件的增量过小。如果文件的增量与写入 tempdb 的数据量相比过小,则 tempdb 可能需要不断扩大。这将影响性能。建议为 tempdb 文件设置 FILEGROWTH 增量时遵循以下通用原则。
tempdb 文件大小
FILEGROWTH 增量
0 至 100 MB
10 MB
100 至 200 MB
20 MB
200 MB 或更多
10%*
* 您可能必须基于 tempdb 文件所在的 I/O 子系统的速度调整此百分比。为了避免潜在的闩锁超时,我们建议将自动增长操作限制在大约两分钟之内。例如,如果 I/O 子系统以每秒 50 MB 的速度初始化文件,则无论 tempdb 文件的大小如何,FILEGROWTH 增量都应设置为最大值 6 GB。如果可能,请使用实例数据库文件初始化来提高自动增长操作的性能。
-
通过将文件大小设置为足够容纳环境中典型工作负荷的值来预分配所有 tempdb 文件的空间。这可以避免 tempdb 因扩展得过于频繁而影响性能。tempdb 数据库应设置为自动增长,但是在出现意外情况时此设置将用于增加磁盘空间。
-
根据需要创建足够多的文件以使磁盘宽度最大化。使用多个文件可以减少 tempdb 存储争用并获得更大的可伸缩性。但是,请勿创建过多的文件,因为此操作可能降低性能并增加管理开销。作为通用原则,为服务器中的每一个 CPU 创建一个数据文件(用于解释任何关联掩码设置),然后根据需要上下调整文件的数量。请注意,双核心 CPU 将被视为两个 CPU。
-
使每个数据文件的大小相同,这样可以优化比例填充的性能。
-
将 tempdb 数据库放置在快速 I/O 子系统中。如果有许多直接连接的磁盘,则请使用磁盘条带化。
-
将 tempdb 数据库放置在用户数据库使用的磁盘以外的磁盘中。