RDS SQL Server空间不足问题

重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

RDS SQL Server实例的空间使用率是日常需要重点关注的监控项之一,实例的存储空间不足,会导致严重后果,例如数据库无法写入、数据库无法备份、存储空间扩容任务耗时过长等。本文介绍如何查看空间使用情况以及排查空间问题。

查看空间使用情况

  • 方法一:您可以在实例的基本信息页面查看存储空间使用情况,但此页面只展示当前的空间使用总量,不会展示各类数据分别占用的磁盘空间信息,也没有空间使用的历史信息。基本信息

  • 方法二:您可以在实例的监控与报警页面,在标准监控页面下查看实例各类数据占用的磁盘空间信息和历史变化曲线。各类指标含义,请参见查看标准监控

    image

  • 方法三:您可以在控制台的自治服务 > 空间管理页面,查看更详细的空间使用情况,包括数据与日志的空间使用对比、空间使用的历史变化趋势、Top数据库和Top表的空间分配明细等。更多信息,请参见空间管理

    说明

    不支持RDS SQL Server 2008 R2云盘版实例。

    image

  • 方法四:您也可以使用客户端工具(例如SSMS),查看实例的空间使用信息。相关操作,请参见通过SSMS客户端连接RDS SQL Server实例

    常用的查看SQL Server数据库空间使用信息的命令如下。

    系统视图或命令

    说明

    sp_helpdb

    查看所有数据库各自的总空间大小(数据文件与日志文件大小之和)。

    sp_spaceused

    查看当前数据库的名称、已使用空间大小和未分配空间大小。

    DBCC SQLPERF(LOGSPACE)

    查看所有数据库各自的日志文件总空间大小以及实际已使用日志空间大小。

    DBCC SHOWFILESTATS

    查看当前数据库的所有数据文件空间大小以及实际已使用数据空间大小。

    SELECT * FROM sys.master_files

    查看所有数据库各自的数据和日志文件的大小。

    SELECT * FROM sys.dm_db_log_space_usage

    查看当前数据库的日志空间总空间和实际已使用日志空间大小。仅适用于SQL Server 2012及以上版本。

    SELECT * FROM sys.dm_db_file_space_usage

    查看当前数据库的数据文件总空间和实际已使用数据空间大小。仅适用于SQL Server 2012及以上版本。

如果发现实例的空间使用率过高,首先应该在RDS管理控制台监控与报警页面中检查数据、日志、临时文件、其他文件各部分的空间使用情况,确认是哪种文件的空间增长过快,并进一步评估能否采取措施释放空间或避免空间快速增长。详细的分析与解决方案请参见下文。

回收和释放数据空间

分析原因

数据空间的总大小(即所有数据文件大小总和)是由已分配(Allocated)空间和未分配(Unallocated)空间两部分组成:

  • 已分配空间包括已使用(Used)空间和未使用(Unused)空间,未使用空间只能分配给同一表或索引新增的记录使用,其他数据库对象无法直接使用。

  • 未分配空间是由完全未分配的区(Extent)构成的,每个区是连续的64 KB空间。未分配空间不和任何数据库对象关联,这部分空间可以通过收缩文件的方式释放。

在数据量持续增长的情况下,未分配空间通常很小,所以直接收缩文件效果很差,建议首先对已分配空间进行优化和回收,然后再考虑收缩文件

回收数据空间

通常数据空间的回收有如下几种方式:

  • 归档数据

    删除数据库中不常用的数据(例如早期的历史数据),或者根据需要迁移到其他数据库实例中,或者以其他形式归档保存,通过直接减少数据量来降低已使用数据空间大小。

    这种方式是控制数据空间增长的有效手段,但是对数据库对象结构及相关应用逻辑的设计有一定要求,需要应用设计和开发人员的参与配合。

  • 压缩数据

    SQL Server 2016及以上版本实例,或2016以下的企业版实例,内置数据压缩功能,您可以在单个表、索引或分区上开启压缩功能,包括行压缩和页压缩。更多信息,请参见Data Compression

    数据压缩比由表结构、列的数据类型和数值分布情况等决定,跨度较大,例如从10%到90%。SQL Server中提供了一个专用的存储过程sp_estimate_data_compression_savings可以帮助您快速评估在指定的表或索引上开启压缩可以节省多少数据存储空间。

    说明
    • 修改表或索引上的压缩选项设置是DDL操作,大表执行此类操作会造成长时间锁表,可能影响业务,建议在业务低峰期修改。

    • RDS SQL Server企业版实例可以设置参数ONLINEON,然后执行修改操作,基本不会影响正常业务。

    • 数据压缩会增加CPU开销,因此需要根据实际业务情况进行评估,建议只在大表上启用数据压缩。

  • 整理索引碎片

    索引碎片率较高会导致实际占用的数据存储空间过大,因此对索引执行碎片整理可以降低数据空间大小。

    您可以在控制台的自治服务 > 性能优化页面,单击索引使用率页签,可以查看各表的索引碎片率统计结果,并且自治服务会提供索引重建(Rebuild)或重组(Reorganize)建议。

    整理索引碎片

    • 重建(Rebuild)操作

      优化效果较好,对于碎片率高的情况执行效率更高,默认情况下执行过程中会锁表,企业版中可以设置参数ONLINEON避免长时间锁表。

    • 重组(Reorganize)操作

      对于碎片率较低的情况执行效率更高,但优化效果不如重建。

    索引碎片率统计的是逻辑上相邻的索引页在物理位置上不一致的比例,和索引页中的空闲空间比例不是一个概念,只是碎片率较高的索引大概率也是可回收空间比例较大的索引。

    如果需要分析某个索引的页内平均空闲空间比例,可以使用SAMPLEDDETAILED模式查询系统视图sys.dm_db_index_physical_stats,然后参考结果集中avg_page_space_used_in_percent列的值。更多信息,请参见sys.dm_db_index_physical_stats (Transact-SQL)

    说明

    查询过程会读取大量索引页,可能影响数据库性能,请在业务低峰期操作。

    整理索引碎片只适用于更新频率很低的归档数据表,如果有频繁的插入和更新操作,索引碎片率会很快升高,而且重建或重组的过程中,会产生大量事务日志,导致日志空间的增加。

收缩数据文件

上文数据空间回收操作通常可以有效降低数据空间大小,但如果实例空间仍然有压力,可以通过以下两种方式解决:

重要

单次对SQL Server数据库进行大范围收缩可能导致大量事务日志增长和长时间阻塞,建议使用方式一循环小批次进行收缩

  • 方式一:分批次循环收缩数据文件,建议每次收缩5 GB。示例如下:

    DECLARE @dbName NVARCHAR(128) = 'YourDatabaseName'  -- 数据库名称
    DECLARE @fileName NVARCHAR(128)  -- 数据文件名
    DECLARE @targetSize INT = 1024   -- 目标大小(MB)
    DECLARE @shrinkSize INT = 5120   -- 循环收缩时每次收缩的大小(MB),建议每次5GB
    DECLARE @currentSize INT         -- 当前大小
    DECLARE @sql NVARCHAR(500)       
    DECLARE @waitTime INT = 10      -- 每次收缩后等待时间(秒)
    
    -- 获取数据文件名
    SELECT @fileName = name
    FROM sys.master_files
    WHERE database_id = DB_ID(@dbName)
    AND type_desc = 'ROWS'
    
    -- 循环收缩
    WHILE 1 = 1
    BEGIN
        -- 获取当前文件大小
        SELECT @currentSize = size/128
        FROM sys.database_files
        WHERE name = @fileName
        
        -- 如果达到目标大小则退出
        IF @currentSize <= @targetSize
        BEGIN
            PRINT '收缩完成,当前大小: ' + CAST(@currentSize AS VARCHAR(20)) + 'MB'
            BREAK
        END
        
        -- 计算本次收缩后的大小
        DECLARE @newSize INT = @currentSize - @shrinkSize
        IF @newSize < @targetSize
            SET @newSize = @targetSize
            
        -- 执行收缩
        SET @sql = 'DBCC SHRINKFILE (N''' + @fileName + ''', ' + CAST(@newSize AS VARCHAR(20)) + ')'
        PRINT '执行收缩: ' + @sql
        EXEC (@sql)
        
        -- 等待一段时间后继续
        PRINT '等待 ' + CAST(@waitTime AS VARCHAR(10)) + ' 秒后继续...'
        WAITFOR DELAY '00:05:00'
    END
  • 方式二:执行DBCC SHRINKFILE命令直接收缩单个数据文件,将数据文件中未分配空间释放给操作系统。更多信息,请参见Shrink a DatabaseDBCC SHRINKFILE (Transact-SQL)

    DBCC SHRINKFILE(<文件ID>, <期望收缩后的大小(单位MB)>)

    点击展开查看示例

    案例以上图为例,一个区(Extent)的大小为64 KB,数据文件的总空间大小为(1673344 x 64)/ 1024 = 104584 MB,已分配空间为(1313432 x 64)/ 1024 = 82089.5 MB,即压缩后数据文件空间的总大小不会低于82089.5 MB 。因此要将该数据文件空间的总大小缩小到90000 MB,可执行如下命令:

    DBCC SHRINKFILE(1, 90000)

回收日志空间

查看已使用日志空间

回收日志空间比较简单,使用DBCC SQLPERF(LOGSPACE)命令或自治服务查看数据库的日志文件空间中实际已使用部分的比例。如果已使用部分的比例较高,收缩日志文件几乎没有效果,可以查询系统视图sys.databases,通过log_reuse_waitlog_reuse_wait_desc列的输出信息判断空间为何无法回收。

说明

log_reuse_waitlog_reuse_wait_desc的取值说明,请参见sys.databases (Transact-SQL)

收缩事务日志

警告

如果您的数据库服务器提示“事务日志已满”,此时无法通过控制台收缩事务日志,您可以手动执行SQL语句进行处理,但该方案有使用风险,具体请参见日志空间不足时的解决方案(仅适用于紧急状态时进行)日志空间不足时,一般建议您先扩容磁盘

特性

方案一:单个数据库收缩(仅收缩不备份)

方案二:实例级备份并收缩(先备份再收缩)

操作范围

单个数据库

整个实例

是否备份

不备份

自动备份所有事务日志

空间回收速度

快速

较慢(需先备份再收缩)

适用场景

日志增长快、无法等到下次实例级全量或增量备份(急需空间回收)

日志空间充足(收缩事务日志会占用部分日志空间)、需全局优化

对其他数据库的影响

无影响

影响整个实例

操作方法

收缩数据库事务日志

备份并收缩事务日志

收缩完成后,您可前往RDS实例详情页监控与报警页面,查看最新的日志空间情况。

image

回收临时文件空间

分析原因

临时文件空间是指系统数据库tempdb占用的空间大小。由于tempdb库总是使用简单恢复模式,因此tempdb库的日志文件通常很小,但是数据文件容易快速增长,例如创建大量临时表、连接大表或排序等都可能导致tempdb库数据文件空间增加。

解决方案

  • 尽量从数据库应用层面规避,例如减少不必要的临时表、大表连接查询、避免大事务等。

  • 在业务低峰期重启RDS实例,重启后tempdb库占用的空间会恢复到实例创建时的大小。

回收其他文件空间

分析原因

其他文件空间在此指sqlserver.other_sizemastersizemodelsizemsdbsize等占用的空间大小。这些文件通常都很小,但是某些情况下占用的空间会很大,例如:

  • 错误日志errorlog较多,错误日志文件大小增长到几GB甚至更大。

  • 严重异常时自动产生的内存转储(memory dump)文件。

解决方案

  1. 您可以在RDS实例详情页监控与报警页面的标准监控页签下,查看这些文件所占用的空间大小。各类指标含义,请参见查看标准监控

    image

  2. errorlog占用较大,您可在日志管理页面对错误日志进行清理。具体操作,请参见管理日志

    说明

    若出现其他文件(例如sqlserver.other_size)占用过大的情况,请联系技术支持人员,技术支持人员会协助您锁定原因并处理。

扩容存储空间

如果RDS实例空间使用率过高,且参考上文后无法有效降低空间使用率,建议及时扩容实例存储空间。具体操作,请参见变更配置