数据库存储空间使用率是我们运维中需要必不可少的一个资源监控点,甚至说它的监控要比CPU、内存、IO使用率还要重要。当SQL Server实例磁盘使用率达到高水位时,我们首先需要判断究竟是哪部分空间的空间占用最大,然后再进行对应的措施考虑是否可以释放空闲空间,本章考虑的是当SQL Server事务日志空间使用率较高时,我们应该如何排查定位以及处理。

1 定位空间瓶颈点

1.1 OS层面

操作系统层面,可以直接查各个磁盘目录文件大小定位磁盘空间消耗最大数据库文件。

1.2 数据库层面

通过数据库查询系统表定位数据库实例磁盘消耗最大文件

SELECT DB_NAME(database_id) AS [Database Name],[Name] AS [Logical Name],[Physical_Name] AS [Physical Name],((size * 8) / 1024) AS [Size(MB)]
FROM sys.master_files
ORDER BY [Size(MB)] DESC

2 事务日志空间收缩

2.1 事务日志备份收缩

我们空间瓶颈或者异常的定位,我们可以具体的定位到是哪一数据库的事务日志空间存在问题,所以接下来我们需要查看该数据库的事务日志状态,查看事务日志是否可以直接进行收缩

SELECT [name],[recovery_model_desc],[log_reuse_wait_desc]
FROM master.sys.databases

数据库恢复模式区别:

  • SIMPLE : 简单模式下,当数据库进行checkpoint时会自动对事物日志进行截断,该模式下事物日志一般不会太大
  • FULL : 完整恢复模式下,需要通过事物日志备份对事物日志进行截断,否则事物日志空间会不断增长

需要重点关注log_reuse_wait_desc的状态值:

  • NOTHING :目前存在一个或者多个可复用的虚拟日志文件(VLF),事务日志在当前状态下是可以进行收缩的
  • CHECKPOINT : 自上一次日志截断后还未发生checkpoint或是事务日志使用还未超过一个VLF,也是事务日志长时间未被截断的原因之一
  • LOG_BACKUP : 需要进行一次事务日志备份后,才可进行事务日志截断(Full or Bulk-logged recover model),当进行第二次事务日志备份后,事务日志空间才会成为NOTHING状态
  • ACTIVE_BACKUP_OR_RESTORE :当前数据库正处于数据备份或者数据恢复状态
  • ACTIVE_TRANSACTION : 数据库中存在活跃事务导致无法进行事务日志截断,长事物不仅可能会导致当前数据库事务日志空间的增长,也可能会导致tempdb数据库事务日志空间暴涨
  • DATABASE_MIRRORING : 数据库镜像被中断或者有较大延迟

更多状态以及状态解释可参考:https://docs.microsoft.com/en-us/sql/relational-databases/logs/the-transaction-log-sql-server?view=sql-server-ver15

不同的log_reuse_wait_desc状态下,我们对应的处理方式不一致:

1、若log_reuse_wait_desc为ACTIVE_TRANSACTION,表示当前数据库有活跃事务一直未提交。我们需要优先处理活跃事务,才能进行后续的事务日志备份进行日志截断、最终进行事务日志空间收缩操作

1)定位活跃事务,可重点关注sys.dm_tran_database_transactions表信息

-- 查看执行时间超过10分钟的活跃事务
SELECT  ST.session_id,ST.transaction_id AS TransactionID ,  DB_NAME(DT.database_id) AS DatabaseName ,  AT.transaction_begin_time AS TransactionStartTime ,  DATEDIFF(minute, AT.transaction_begin_time, GETDATE()) AS Tran_run_time ,  CASE AT.transaction_type  WHEN 1 THEN 'Read/Write Transaction'  WHEN 2 THEN 'Read-Only Transaction'  WHEN 3 THEN 'System Transaction'  WHEN 4 THEN 'Distributed Transaction'  END AS TransactionType ,  CASE AT.transaction_state  WHEN 0 THEN 'Transaction Not Initialized'  WHEN 1 THEN 'Transaction Initialized & Not Started'  WHEN 2 THEN 'Active Transaction'  WHEN 3 THEN 'Transaction Ended'  WHEN 4 THEN 'Distributed Transaction Initiated Commit Process'  WHEN 5 THEN 'Transaction in Prepared State & Waiting Resolution'  WHEN 6 THEN 'Transaction Committed'  WHEN 7 THEN 'Transaction Rolling Back'  WHEN 8 THEN 'Transaction Rolled Back'  END AS TransactionState
FROM    sys.dm_tran_session_transactions AS ST  INNER JOIN sys.dm_tran_active_transactions AS AT ON ST.transaction_id = AT.transaction_id  INNER JOIN sys.dm_tran_database_transactions AS DT ON ST.transaction_id = DT.transaction_id
WHERE DATEDIFF(minute, AT.transaction_begin_time, GETDATE())>10 -- 找出运行时间大于10分钟的事务
ORDER BY TransactionStartTime  -- 获取长时间未完成的活跃事务SPID
DBCC OPENTRAN-- 查看对应SPID信息
select * from sys.sysprocesses where spid=${SPID}

2)将活动事务进行kill

DBCC INPUTBUFFER(${SPID})

3)将数据库活跃事务进行kill完毕后,事务日志状态可正常转变为LOG_BACKUP,LOG_BACKUP状态下的处理方式具体参考如下

2、若log_reuse_wait_desc为LOG_BACKUP,表示事务日志未进行日志备份,需要进行事务日志备份后才可进行截断、事务日志空间收缩的操作

1)若数据库事务日志从未进行过备份,那么必须进行两次事务日志备份后,事务日志才可被截断,且状态转变成为NOTHING,此时事务日志被可正常进行数据日志收缩。相关参考文档连接为:https://docs.microsoft.com/en-us/sql/relational-databases/logs/troubleshoot-a-full-transaction-log-sql-server-error-9002?view=sql-server-2017

2)若数据库事务日志之前有过备份,那么可直接对当前事务日志进行备份,备份后事务日志截断且状态转变为NOTHING,表示事物已经被截断完成

--事物日志备份命令
BACKUP LOG [dbname] TO DISK = 'some_volume:\some_folder\dbname_LOG.trn'

3)检查数据库事物日志状态与使用率

-- 检查数据库文件空间使用率
SELECT a.name [文件名称] ,cast(a.[size]*1.0/128 as decimal(12,1)) AS [文件设置大小(MB)] ,CAST( fileproperty(s.name,'SpaceUsed')/(8*16.0) AS DECIMAL(12,1)) AS [文件所占空间(MB)] ,CAST( (fileproperty(s.name,'SpaceUsed')/(8*16.0))/(s.size/(8*16.0))*100.0 AS DECIMAL(12,1)) AS [所占空间率%] ,CASE WHEN A.growth =0 THEN '文件大小固定,不会增长' ELSE '文件将自动增长' end [增长模式] ,CASE WHEN A.growth > 0 AND is_percent_growth = 0 THEN '增量为固定大小' WHEN A.growth > 0 AND is_percent_growth = 1 THEN '增量将用整数百分比表示' ELSE '文件大小固定,不会增长' END AS [增量模式] ,CASE WHEN A.growth > 0 AND is_percent_growth = 0 THEN cast(cast(a.growth*1.0/128as decimal(12,0)) AS VARCHAR)+'MB' WHEN A.growth > 0 AND is_percent_growth = 1 THEN cast(cast(a.growth AS decimal(12,0)) AS VARCHAR)+'%' ELSE '文件大小固定,不会增长' end AS [增长值(%或MB)] ,a.physical_name AS [文件所在目录] ,a.type_desc AS [文件类型]
FROM sys.database_files a
INNER JOIN sys.sysfiles AS s  ON a.[file_id]=s.fileid
LEFT JOIN sys.dm_db_file_space_usage b ON a.[file_id]=b.[file_id] ORDER BY a.[type]-- 检查事物日志状态,将要收缩的事物日志状态为NOTHING
SELECT [name],[recovery_model_desc],[log_reuse_wait_desc]
FROM master.sys.databases

4)对事物日志进行空间收缩

USE [${DB_Name}]
DBCC SHRINKFILE (N'db1' , 0, TRUNCATEONLY)

2.2 变更数据库恢复模式释放空间

当数据库服务器磁盘空间已经基本打满,没有多余的空间用来进行事物日志备份,那么需要通过变更数据库恢复模式来将数据库日志进行截断,然后进行空间收缩处理。变更数据库恢复模式与上面备份事物日志后处理相对,

1、变更数据库恢复模式进行事物日志收缩流程

1)变更数据库恢复模式,将数据库恢复模式设置为simple模式,该模式下当数据库进行checkpoint时会自动对事物日志进行截断

alter database [$DB_Name] set recovery simple

2)检查事物日志状态以及事物日志空间利用率,确定截断操作完成

-- 检查数据库文件空间使用率
SELECT a.name [文件名称] ,cast(a.[size]*1.0/128 as decimal(12,1)) AS [文件设置大小(MB)] ,CAST( fileproperty(s.name,'SpaceUsed')/(8*16.0) AS DECIMAL(12,1)) AS [文件所占空间(MB)] ,CAST( (fileproperty(s.name,'SpaceUsed')/(8*16.0))/(s.size/(8*16.0))*100.0 AS DECIMAL(12,1)) AS [所占空间率%] ,CASE WHEN A.growth =0 THEN '文件大小固定,不会增长' ELSE '文件将自动增长' end [增长模式] ,CASE WHEN A.growth > 0 AND is_percent_growth = 0 THEN '增量为固定大小' WHEN A.growth > 0 AND is_percent_growth = 1 THEN '增量将用整数百分比表示' ELSE '文件大小固定,不会增长' END AS [增量模式] ,CASE WHEN A.growth > 0 AND is_percent_growth = 0 THEN cast(cast(a.growth*1.0/128as decimal(12,0)) AS VARCHAR)+'MB' WHEN A.growth > 0 AND is_percent_growth = 1 THEN cast(cast(a.growth AS decimal(12,0)) AS VARCHAR)+'%' ELSE '文件大小固定,不会增长' end AS [增长值(%或MB)] ,a.physical_name AS [文件所在目录] ,a.type_desc AS [文件类型]
FROM sys.database_files a
INNER JOIN sys.sysfiles AS s  ON a.[file_id]=s.fileid
LEFT JOIN sys.dm_db_file_space_usage b ON a.[file_id]=b.[file_id] ORDER BY a.[type]-- 检查事物日志状态,将要收缩的事物日志状态为NOTHING
SELECT [name],[recovery_model_desc],[log_reuse_wait_desc]
FROM master.sys.databases

3)变更数据库恢复模式为full

alter database [$DB_Name] set recovery full

2、变更数据库恢复模式进行空间回收的风险

将数据库模式变更为Simple模式,主要是为了快速对数据库事物日志进行截断,当数据库Checkpoint时会自动对数据库事物日志截断。其风险就是该数据库的事物日志丢失,后续将无法对该事物日志包含时间点数据进行按时间点恢复。

该方式下,建议变更完毕后,立即对数据库进行一次全量物理备份,保证变更后时间节点可正常进行数据恢复。

3 预防操作

3.1 事物日志暴涨常见场景

常见的事物日志暴涨的场景如下:

  • 大事物
  • 阻塞事物日志截断的操作
    • FULL恢复模式下,未设置合理的数据库全量备份+事物日志备份
    • 长事物,事物日志状态长时间为ACTIVE_TRANSACTION
    • Checkpoint操作延迟
  • 日志初始值以及日志增长设置不合理,导致事物日志一次性扩展较大空间

3.2 事物日志暴涨预防

为防止数据库事物日志暴涨,我们需要检查如下几点:

  • 完善的数据库备份策略,数据库完整备份+事物日志备份,Full恢复模式下,需要通过事物日志备份来保证数据库事物日志的截断
  • 合理的数据库事物日志设置:初始化大小、自动增长策略
  • 合理的拆分事物,避免长事物、大事物

相关官方文档可参考:https://docs.microsoft.com/en-us/sql/relational-databases/logs/troubleshoot-a-full-transaction-log-sql-server-error-9002?view=sql-server-ver15

SQL Server 事物日志空间收缩相关推荐

  1. SQL Server 2008R2 日志文件收缩

    下面的数据库为要收缩的数据库名称 –SQL Server 2008R2 收缩日志 ----------改变数据库模式(简单) alter database 数据库 set recovery simpl ...

  2. 10个最重要SQL Server事务日志神话

    Myth: SQL transaction log truncation will make it smaller 误解: SQL事务日志截断将使其变小 The truncation process ...

  3. SQL Server事务日志采访问题

    In this article, we will discuss some important SQL Server Transaction Log interview questions that ...

  4. SQL Server自动化运维系列——监控磁盘剩余空间及SQL Server错误日志(Power Shell)...

    原文:SQL Server自动化运维系列--监控磁盘剩余空间及SQL Server错误日志(Power Shell) 需求描述 在我们的生产环境中,大部分情况下需要有自己的运维体制,包括自己健康状态的 ...

  5. SQL server数据库日志满了怎么处理?

    日志文件满而造成SQL数据库无法写入文件时,可用两种方法: 一种方法:清空日志. 1.打开查询分析器,输入命令 DUMP TRANSACTION 数据库名 WITH NO_LOG 2.再打开企业管理器 ...

  6. SQL Server 事务日志的问题

    关于SQL SERVER 日志满的处理方法 事务日志文件Transaction Log File是用来记录数据库更新情况的文件,扩展名为ldf. 在 SQL Server 7.0 和 SQL Serv ...

  7. Sql Server事务日志

    本文导读:SQL Server中的数据库都是由一或多个数据文件以及一或多个事务日志文件组成的.SQL Server事务日志主要是用来记录所有事务对数据库所做的修改,SQL SERVER利用事务日志来确 ...

  8. 如何使用损坏或删除SQL Server事务日志文件重建数据库

    This is the last article, but not the least one, in the SQL Server Transaction Log series. In this s ...

  9. SQL Server事务日志备份,截断和缩减操作

    In this article, we will cover SQL Server Transaction log backups, truncate and shrink operations wi ...

最新文章

  1. 再回首数据结构—链表
  2. mockito_使用Mockito模拟自动装配的字段
  3. hdu4740 不错的简单搜索
  4. [cocos2d-x·总结]关于cocos2d-x几种画图方法的用法与思考
  5. 如何优化JavaScript脚本的性能
  6. Linux socket编程(二) 服务器与客户端的通信
  7. 计算机学硕专业课可以自学吗,考研专业课怎么考?高效复习法三条就够!
  8. pip3 安装pycrypto 时报错
  9. iMAG移动应用快速开发平台简介
  10. 微软源代码遭 SolarWinds 黑客访问
  11. 如何“ grep”连续流?
  12. 利用openssl进行base64的编码与解码
  13. 实现option上下移动_jQuery操作Select的Option上下移动及移除添加等等
  14. Redis 查看key的有效时间
  15. cad通过钢筋大样生成钢筋明细表插件_易图(CAD插件For2016-2018)下载|易图(CAD插件For2016-2018)官方版下载_v18.3.1_9号软件下载...
  16. 计算机电子表格证怎么样,初学者在电脑上如何制作电子表格
  17. [VBA学习]关于Formula以及数字格式的问题
  18. 古诗名句分类二:事理哲理
  19. php查询mysql显示在html表格中_php – 在网页上的HTML表格中显示MySQL数据库表中的值...
  20. 《机器学习实战》(八)-- 树回归

热门文章

  1. 理想倍频器/分频器对相噪/杂散的影响
  2. 人生何处不相逢谐音歌词
  3. linux备份当前目录压缩,Linux备份压缩命令:tar详解
  4. 【MATLAB】GNSS观测文件采样频率1Hz转换为10Hz
  5. H5性能优化报告以及方案模板
  6. 阿里开源工具——故障在线诊断Arthas
  7. 知道RAD Studio Sydney(Delphi 10.4.2)这些,少走弯路
  8. 标签打印软件如何制作珠宝标签
  9. BarTender从数据库获取标签打印数量设置方法
  10. 全靠这份阿里P5-P9知识核心手册+10W字面试题总结,让我在22岁月薪35k!