SQL Server 2014中Tempdb数据文件增长很快?

pre*_*mar 3 tempdb sql-server-2014

几天前,我们已经从 2012 年服务器迁移到 2014 年,我们保留了与之前相同的设置,例如我们在 Tempdb 中使用 8 个数据文件以获得更好的性能,并且全部放置在单个驱动器中。

由于这是数据仓库环境,批量加载连续运行,并且 tempdb 驱动器已满。即使数据库中有 98% 的可用空间,它也无法重用空间并导致磁盘已满。

tempdb 中没有足够的空间来保存行版本。需要缩小版本存储以释放 tempdb 中的一些空间。事务(id=239368387 xsn=1273322 spid=126 elapsed_time=1590)已被标记为受害者,如果它访问版本存储,它将被回滚。如果问题仍然存在,可能的原因是临时数据库大小不正确或事务长时间运行。请参阅 BOL 了解如何配置 tempdb 进行版本控制。

问题

  1. SQL Sever 2014 中是否有任何特定的 tempdb 设置可以避免这些问题?

  2. 对于 tempdb 性能改进有什么建议,例如启用跟踪标志 -T1118 吗?

2012 年,它只需要 64 GB,现在甚至 450 GB 也不够用。

服务器规范。

SQL Server 检测到 4 个插槽,每个插槽 15 个核心,每个插槽 30 个逻辑处理器,总共 120 个逻辑处理器;使用基于 SQL Server 许可的 120 个逻辑处理器。512 GB 内存。

The*_*war 5

在对 TempDB 空间进行故障排除之前,最好了解哪些对象正在使用 TempDB。

即使您只遇到版本存储方面的问题,了解哪些对象正在使用 TempDB 会让您更好地了解从哪里开始。

请记住,TempDB 是所有数据库的全局资源,因此这将用于所有数据库。在较高级别上,这些是可以使用 TempDB 的对象:

1. 用户对象

  • 用户定义的表和索引
  • 系统表和索引
  • 全局临时表和索引
  • 本地临时表和索引
  • 表变量
  • 表值函数中返回的表

2. 内部对象

这些是 SQL Server 创建的内部对象,用于工作表、哈希联接、排序......

3.版本存储

  • 触发器
  • 火星
  • 在线索引
  • 基于行版本的隔离级别:需要在数据库级别设置

另外Cursors、Database Mail、DBCC CHECKDB也可以使用TempDB。请参阅这篇文章了解更多详细信息Capacity Planning for tempdb

现在我们知道了 TempDB 的使用方式,我们可以使用 SQL Server 提供的 DMVS 来跟踪 TempDB 空间利用率

跟踪消耗最多空间的用户对象:

用户对象使用的空间:(仅限活动)

   WITH task_space_usage AS (
    -- SUM alloc/delloc pages
    SELECT session_id,
           request_id,
           SUM(internal_objects_alloc_page_count) AS alloc_pages,
           SUM(internal_objects_dealloc_page_count) AS dealloc_pages
    FROM sys.dm_db_task_space_usage WITH (NOLOCK)
    WHERE session_id <> @@SPID
    GROUP BY session_id, request_id
)
SELECT TSU.session_id,
       TSU.alloc_pages * 1.0 / 128 AS [internal object MB space],
       TSU.dealloc_pages * 1.0 / 128 AS [internal object dealloc MB space],
       EST.text,
       -- Extract statement from sql text
       ISNULL(
           NULLIF(
               SUBSTRING(
                 EST.text, 
                 ERQ.statement_start_offset / 2, 
                 CASE WHEN ERQ.statement_end_offset < ERQ.statement_start_offset 
                  THEN 0 
                 ELSE( ERQ.statement_end_offset - ERQ.statement_start_offset ) / 2 END
               ), ''
           ), EST.text
       ) AS [statement text],
       EQP.query_plan
FROM task_space_usage AS TSU
INNER JOIN sys.dm_exec_requests ERQ WITH (NOLOCK)
    ON  TSU.session_id = ERQ.session_id
    AND TSU.request_id = ERQ.request_id
OUTER APPLY sys.dm_exec_sql_text(ERQ.sql_handle) AS EST
OUTER APPLY sys.dm_exec_query_plan(ERQ.plan_handle) AS EQP
WHERE EST.text IS NOT NULL OR EQP.query_plan IS NOT NULL
ORDER BY 3 DESC;
Run Code Online (Sandbox Code Playgroud)

内部对象使用的空间((仅限活动)):

SELECT 
    t1.session_id, 
    t1.request_id, 
    t1.task_alloc,
    t1.task_dealloc,
    t2.sql_handle, 
    t2.statement_start_offset, 
    t2.statement_end_offset, 
    t2.plan_handle
FROM (SELECT session_id, 
             request_id,
             SUM(internal_objects_alloc_page_count) AS task_alloc,
             SUM(internal_objects_dealloc_page_count) AS task_dealloc 
      FROM sys.dm_db_task_space_usage 
      GROUP BY session_id, request_id) AS t1, 
      sys.dm_exec_requests AS t2
WHERE t1.session_id = t2.session_id AND 
     (t1.request_id = t2.request_id)
ORDER BY t1.task_alloc DESC
Run Code Online (Sandbox Code Playgroud)

版本存储: 您可以找到正在使用版本存储的交易列表。要查看它们占用了多少空间,请参阅最后的文章

SELECT top 2 
    transaction_id, 
    transaction_sequence_num, 
    elapsed_time_seconds 
FROM sys.dm_tran_active_snapshot_database_transactions
Run Code Online (Sandbox Code Playgroud)

交易完成后,交易使用的空间将自动清理。如果事务长时间打开,它将阻止版本存储清理,您可能必须通过加入 sys.dm_exec_sessions 或 sys.sysprocesses 来检查原因

您还可以自动收集此空间使用情况以供以后分析。

这只是为了给您提供想法,但它可能不适用于您的版本,因为某些列可能已更改。

查询以收集详细信息:

CREATE PROC sp_sampleTempDbSpaceUsage AS
  Instance level tempdb FILE space usage FOR ALL files WITHIN 
  -- tempdb
  INSERT tempdb_space_usage (
    scope,
    Instance_unallocated_extent_pages,
    version_store_pages,
    Instance_userobj_alloc_pages,
    Instance_internalobj_alloc_pages,
    Instance_mixed_extent_alloc_pages)
  SELECT 
    'instance',
    SUM(unallocated_extent_page_count),
    SUM(version_store_reserved_page_count),
    SUM(user_object_reserved_page_count),
    SUM(internal_object_reserved_page_count),
    SUM(mixed_extent_page_count)
  FROM sys.dm_db_file_space_usage

    -- 2. tempdb space usage per session 
    --
  INSERT tempdb_space_usage (
    scope,
    session_id,
    Sess_task_userobj_alloc_pages,
    Sess_task_userobj_deallocated_pages,
    Sess_task_internalobj_alloc_pages,
    Sess_task_internalobj_deallocated_pages)
  SELECT
    'session', 
    session_id,
    user_objects_alloc_page_count,
    user_objects_dealloc_page_count,
    internal_objects_alloc_page_count,
    internal_objects_dealloc_page_count
  FROM sys.dm_db_session_space_usage
    WHERE session_id > 50
    -- 3. tempdb space usage per active task
    --
  INSERT tempdb_space_usage (
    scope,
    session_id,
    Sess_task_userobj_alloc_pages,
    Sess_task_userobj_deallocated_pages,
    Sess_task_internalobj_alloc_pages,
    Sess_task_internalobj_deallocated_pages,
    query_text)
  SELECT 
    'task',
    R1.session_id,
    R1.user_objects_alloc_page_count,
    R1.user_objects_dealloc_page_count,
    R1.internal_objects_alloc_page_count,
    R1.internal_objects_dealloc_page_count,
    R3.text
  FROM sys.dm_db_task_space_usage AS R1
    LEFT OUTER JOIN
    sys.dm_exec_requests AS R2
    ON R1.session_id = R2.session_id 
    OUTER APPLY sys.dm_exec_sql_text(R2.sql_handle) AS R3
  WHERE R1.session_id > 50
Run Code Online (Sandbox Code Playgroud)

一旦收集了足够的数据,您可以使用以下查询进行分析:

查询 1:此查询报告 TempDB 中针对收集的所有数据点分配的最大空间

SELECT
  CONVERT (float, (MAX(version_store_pages +
      Instance_userobj_alloc_pages +
      Instance_internalobj_alloc_pages +
      Instance_mixed_extent_alloc_pages)))/ 128.0
    AS max_tempdb_allocation_MB
FROM     tempdb_space_usage 
WHERE scope = 'instance'
Run Code Online (Sandbox Code Playgroud)

查询 2:此查询计算收集的所有数据点的最大分配页数和版本存储大小(以兆字节为单位)。如果分配给版本存储的 TempDB 空间量很大,则意味着长时间运行的事务正在生成或消耗版本。

SELECT     
  MAX(version_store_pages) AS max_version_store_pages_allocated,
  MAX(version_store_pages/128.0) AS max_version_store_allocated_space_MB
FROM tempdb_space_usage 
WHERE scope = 'instance' 
Run Code Online (Sandbox Code Playgroud)

查询 3:此查询显示为内部对象分配最多页面的前五个查询。

SELECT top 5 MAX ((Sess_task_internalobj_alloc_pages) - (Sess_task_internalobj_deallocated_pages))
  AS Max_Sess_task_allocated_pages_delta,     query_text
FROM tempdb_space_usage 
WHERE scope = 'task' and session_id > 50
GROUP BY query_text
ORDER BY Max_Sess_task_allocated_pages_delta  DESC
Run Code Online (Sandbox Code Playgroud)

以下是我使用的参考资料,可以进一步帮助您:

  1. https://blogs.msdn.microsoft.com/sqlserverfaq/2010/10/13/troubleshooting-tempdb-growth-due-to-version-store-usage/
  2. 如何识别哪个查询正在填充 tempdb 事务日志?
  3. https://technet.microsoft.com/en-us/library/ms176029(v=sql.105).aspx
  4. https://technet.microsoft.com/en-us/library/cc966545.aspx

以下是必读内容:

  1. https://technet.microsoft.com/en-us/library/dd672789(v=sql.100).aspx
  2. https://technet.microsoft.com/en-us/library/cc966545.aspx