【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

往期分享

RDS MySQL

RDS MySQL 实例空间问题

RDS MySQL 内存使用问题

RDS MySQL 活跃线程数高问题

RDS MySQL 慢SQL问题

RDS MySQL 实例IO高问题

RDS MySQL 小版本升级最佳实践

RDS PostgreSQL

RDS PostgreSQL 实例IO高问题

RDS PostgreSQL 慢SQL问题

RDS PostgreSQL CPU高问题

RDS SQL Server

RDS SQL Server 磁盘IO吞吐高问题

RDS SQL Server CPU高问题


概述

实例的空间使用率是RDS SQL Server用户日常需要重点关注的监控项之一。如果实例的存储空间完全打满,将会导致严重的影响,包括:数据库无法写入、数据库备份无法正常完成、存储空间扩容任务的执行耗时可能更长等。

一般来说,当一个RDS SQL Server实例的存储空间使用比例达到80-85%以上时,就应及时进行处理,要么降低数据库实际占用空间的大小,要么对存储空间进行扩容,以避免空间打满的风险。

查看空间使用情况

RDS控制台

RDS SQL Server的控制台中提供了多种查看实例空间使用情况的方法:

基本信息

在RDS控制台的“基本信息”页中会显示实例的总存储空间使用大小,但这里只有当前的空间使用总量,没有具体的各类数据分别占用空间大小的信息,也没有空间使用的历史信息。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

监控与报警

在RDS控制台的“监控与报警”页中的“标准监控”->“资源监控”下,可以查看实例的各类数据占用的磁盘空间大小的信息,并且会显示各部分空间大小的历史变化曲线。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

其中磁盘空间总体使用量即对应当前实例实际已经使用了的所有存储空间总量,它由如下四个部分组成:

数据空间使用量 所有用户数据库的数据文件(mdf和ndf文件)总大小。
日志空间使用量 所有用户数据库的日志文件(ldf文件)总大小。
临时文件空间使用量 系统数据库tempdb的所有数据文件和日志文件的总大小。
系统文件空间使用量 系统数据库master、msdb和model的所有数据文件和日志文件,以及SQL Server实例目录下的一些系统文件(错误日志、default trace、系统扩展事件文件等)的总大小。


CloudDBA

在RDS控制台的“CloudDBA”->“空间管理”页中可以查看实例内更详细的空间使用情况,包括数据与日志的空间使用对比、空间使用的历史变化趋势、Top数据库和Top表的空间分配明细等。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

这里的“总空间”、“已使用”和“可用空间”均是针对每个数据库的所有数据文件和日志文件的空间总和。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

而在“TOP 20数据表”这个列表中的统计,则是针对数据库中的表所使用的数据文件空间。其中“保留大小”为“数据空间”、“索引空间”、“未使用空间”三部分之和,它们的具体含义如下:

保留大小 已保留给该表的所有空间总和,包括数据、索引及未使用的部分
数据空间 表中的数据使用的总空间
索引空间 表中的所有索引使用的总空间
未使用空间 已保留给该表但还未分配使用的空间

客户端工具

对于RDS SQL Server来说,使用SQL Server客户端工具连接到实例上之后直接查看实例的空间使用信息,也是很方便的。

SQL脚本

以下是一些常用的查看SQL Server数据库空间使用信息的系统视图或命令:

sp_helpdb

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

DBCC SQLPERF(LOGSPACE)

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

sys.master_files

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

sys.dm_db_log_space_usage

查看当前数据库的日志文件的总空间大小以及实际已使用部分的大小

注:适用于SQL Server 2012以上版本

sys.dm_db_file_space_usage

查看当前数据库的所有数据文件各自的总空间大小以及实际已使用部分的大小

注:适用于SQL Server 2012以上版本

DBCC SHOWFILESTATS

查看当前数据库的所有数据文件各自的总空间大小以及实际已使用部分的大小

sp_spaceused

查看当前数据库的总空间大小、已使用空间大小

查看当前数据库的数据文件的保留空间、数据空间、索引空间及未使用空间大小

查看指定表的保留空间、数据空间、索引空间及未使用空间大小

SSMS工具UI

SQL Server Management Studio客户端工具中提供了一些基本的查看数据库空间使用信息的报表,也可以帮助用户比较方便的分析单个数据库内的空间分配使用情况。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

空间回收与释放

当遇到实例的空间使用率过高问题时,应首先从RDS控制台的监控与报警页中检查一下数据、日志、临时文件、系统文件各部分的空间使用情况,看下是哪部分的空间使用占比较高或增长速度较快,并进一步评估能否采取措施释放出部分空间或避免空间的快速增长。

数据空间

对于数据空间占比较高的情况,可首先通过CloudDBA空间管理页或sys.master_files等系统视图检查是哪些数据库的数据空间较大,其中CloudDBA中还可以查看空间使用变化的历史曲线,使用起来更为方便。

对于每个数据库来说,其数据空间的总大小(即其所有数据文件大小的总和)是由已分配的(Allocated)和未分配的(Unallocated)两部分组成的。其中未分配的部分是由完全未分配的Extent(每个为连续的64KB空间)构成的,不和任何数据库对象关联,也只有这部分空间有可能通过文件收缩的方式释放出来给操作系统。而已分配的部分通常都是和特定的数据库对象关联的,其中又包括已使用的(Used)和未使用的(Unused)部分,未使用的部分通常只能分配给同一表或索引新增的记录使用,而无法被其他不同的对象直接使用。

在数据库中的数据量持续增长的情况下,数据文件中的未分配部分通常都是很小的,这也就意味着在未对数据库空间的使用主动进行优化之前,直接尝试收缩数据文件的大小一般不会有什么效果。大部分情况下,若需要控制数据空间的增长并进一步降低其大小的话,都应首先对已分配部分的空间使用进行优化和回收,然后再考虑进行数据文件大小的收缩。

数据空间的回收

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

数据归档

将数据库表中不常用的数据(例如早期的历史数据)从当前表中清除掉,并可根据需要转移到其他数据库实例中,或以其他形式进行归档保存,通过直接减少数据量来降低当前数据库对空间使用的需求。

这种方式如果可行的话,往往是控制数据空间增长量的最有效手段,但它通常对于数据库对象结构及相关应用逻辑的设计也有一定的要求,需要应用设计和开发人员的参与配合。

数据压缩

SQL Server企业版及2016以上的所有版本中提供了内置的数据压缩的功能,用户可以在单个表、索引或其分区上开启压缩功能,并且有行压缩和页压缩两种选项。具体功能说明和使用方法可参见:

https://docs.microsoft.com/en-us/sql/relational-databases/data-compression/data-compression

数据的压缩比和表结构、列的数据类型及数值分布情况等都有很大的关系,从百分之几到90%以上都有可能。SQL Server中提供了一个专用的存储过程sp_estimate_data_compression_savings可以帮助快速评估在指定的表或索引上开启行压缩或页压缩可以节省多大的存储空间:

https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-estimate-data-compression-savings-transact-sql

修改表或索引上的压缩选项设置是一个DDL操作,如果是在SQL Server企业版中执行,可以使用ONLINE=ON参数在线的执行,基本不会影响表上的DML操作的正常执行。而如果是在SQL Server标准版或Web版中,由于不支持ONLINE DDL,对于大表执行此类操作将会造成长时间锁表的情况,并可能对业务中的正常数据库访问造成较大影响,通常应放在维护窗口内执行。

通过在表上开启数据或索引压缩来节省存储空间的方式对数据库应用来说是完全透明的,并且还可以提升数据缓存的效率和降低内存压力,但同时往往也会增加数据存取操作过程中的CPU开销,因此其对数据库整体性能的影响是需要根据具体环境具体评估的。如果实例的CPU资源方面没有瓶颈,而存储空间和缓存压力较大的话,则在主要的大表上启用数据压缩往往是一个比较好的优化选项。

索引碎片整理

当表中的索引的碎片率较高时,除了会降低索引扫描等操作的执行效率,往往还会导致实际占用的存储空间更大。从回收数据空间的角度考虑,对表上的索引执行碎片整理的操作也是一个可行的手段。

CloudDBA的“性能优化”->“索引使用率”页中提供了对数据库中的各表上的索引碎片率统计的结果,并相应的会给出索引重建(Rebuild)或重组(Reorganize)操作的建议:

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

此外,SSMS工具中自带的Index Physical Statistics报表也提供了类似的功能:【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

不过需要注意的是,这里的索引碎片率统计的是逻辑上相邻的索引页在物理位置上不一致的情况的比例,和索引页中的空闲空间比例并不是一个概念,只不过碎片率较高的索引往往也有较大的机会是可回收空间比例较大的索引。如果要分析某个索引的页内平均空闲空间比例的话,可以查询系统视图sys.dm_db_index_physical_stats并使用SAMPLED或DETAILED模式,然后参考结果集中avg_page_space_used_in_percent列的值。同时还要注意的是使用SAMPLED或DETAILED模式查询视图sys.dm_db_index_physical_stats时,会产生大量的索引页读取,并可能对数据库性能造成一定影响,应谨慎操作:

https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-index-physical-stats-transact-sql

对于索引碎片的整理,SQL Server中提供了索引重建(Rebuild)和索引重组(Reorganize)两种操作方式。其中Rebuild的方式往往优化效果更好,对于碎片率高的情况执行效率更高,默认情况下执行过程中会锁表,但在企业版中可以启用Online的模式避免长时间锁表的影响。而Reorganize的操作总是以Online的方式进行,在碎片率较低的情况下执行效率会好一些,但碎片整理的优化效果相对不如Rebuild。

关于碎片整理的更多详细说明,可以参考如下文档:

https://docs.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes

最后,与通过数据压缩进行空间回收的方式不同,虽然通过索引碎片整理往往页可以从数据文件内回收出来一些存储空间,但这个空间使用的减少可能只是临时性的,如果表上仍一直有较频繁的插入和更新操作,那么在清理完索引碎片后,索引碎片率及索引页内的空闲空间比例很可能会快速上升,并导致索引整体存储空间占用的快速增长。因此通过索引碎片整理来控制数据空间增长的方法,主要还是适用于那些很少再更新的归档数据表,或者作为一种临时的空间压力缓解手段。另外,在对大表执行索引重建或重组的过程中,往往会产生大量的事务日志的写入,这期间也要特别关注日志文件大小增长的情况。在RDS SQL Server实例上开启了每30分钟日志备份选项的情况下,通常是可以比较及时的通过日志备份来回收和复用日志文件中的空间的。

数据文件的收缩

从避免实例的数据空间大小持续过快增长的角度考虑,通过上述方式达成了数据空间回收的效果通常就可以了,因为回收出来的空间就可以继续提供给新的数据空间分配需求使用了,而不会造成数据文件大小的持续增长。

但如果确有必要的话,也可以在数据库中执行DBCC SHRINKFILE命令来对数据文件进行收缩,从而将数据文件中未分配的空闲部分空间释放给操作系统,减少整个实例实际占用的磁盘空间大小。

使用DBCC SHRINKFILE命令来对指定的数据文件进行收缩之前,可以先使用DBCC SHOWFILESTATS命令查看各数据文件的大小及其中实际已分配使用部分的大小,已使用的部分是无法被收缩掉的。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

以上图中的执行结果为例,一个Extent的大小为64KB,因此ID为1的数据文件的总空间大小为104584MB,其中已使用的部分大小为82089MB,则该数据文件通过收缩操作可以缩到的最小大小不会低于82089MB。

若要将该数据文件的大小缩小到90000MB,则可以执行如下命令:

DBCC SHRINKFILE(1, 90000)

关于文件收缩操作的更多详细说明,可以参考如下文档:

https://docs.microsoft.com/en-us/sql/relational-databases/databases/shrink-a-database

https://docs.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-shrinkfile-transact-sql

另外要注意的是,数据文件的收缩是一个资源开销较高的操作,会在数据文件上产生大量的磁盘IO,并且还会产生大量的事务日志写入,因此一般应尽量放在实例的负载较低的时候执行。

日志空间

日志空间的回收相对比较简单,首先可以使用DBCC SQLPERF(LOGSPACE)命令或CloudDBA空间管理页查看是哪些数据库的日志文件较大,以及这些库的日志文件中实际已使用部分的比例。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

例如,以上数据库db02的日志文件大小为2312MB,其中已使用的部分比例为99%,这时如果对该数据库的日志文件进行收缩,则几乎不会有任何效果。

这种情况下可首先查询系统视图sys.databases,通过其中log_reuse_wait/log_reuse_wait_desc列的输出信息来判断是什么原因导致事务日志文件中的空间无法被回收:

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

关于log_reuse_wait/log_reuse_wait_desc列的各种取值含义的具体说明详见如下文档:

https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql

其中最常见的一种情况就是LOG_BACKUP。在RDS SQL Server中,数据库默认都是用的完整恢复模式,这种情况下日志文件中记录的内容不会被自动截断(即使事务已提交),而只有完成日志备份的部分才可以被截断和回收复用。另外由于SQL Server日志文件循环写入的结构特点,最多会需要完成两次日志备份之后,已截断部分的日志文件空间才可以被收缩掉。

RDS SQL Server中内置了自动备份的功能,通常每天会自动做一次全量或差异数据备份,并且在数据备份完成后还会自动做一次日志备份。同时在默认设置下,还会每30分钟自动做一次日志备份,从而保障事务日志中的空间可以被及时回收复用。此外在每天一次的数据+日志备份完成之后,还会自动对日志文件执行一次收缩操作,这样即使有一些临时的情况(例如大表的索引重建等大事务)导致日志文件的大小临时增长到很大,通常也会在一天之内恢复到较小的状态。

因此绝大部分情况下,用户没有必要主动对RDS实例上的数据库执行日志文件收缩的操作。另外由于RDS用户没有直接执行数据库或日志备份操作的权限,因此如果出现日志复用等待类型为LOG_BACKUP情况,用户也无法通过先执行BACKUP LOG再执行DBCC SHRINKFILE操作的方式来对日志文件大小进行收缩。

如果确实遇到必须尽快对日志文件大小进行收缩的情况,例如日志文件的增长已经过大导致磁盘可用空间过低,且无法等到下一次的每天定时备份时自动对日志文件进行收缩。则用户可以从RDS控制台的备份恢复页中执行“收缩事务日志”的操作,这时RDS会自动对所有的用户数据库执行事务日志备份及日志文件收缩的操作。

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

由于事务日志的收缩需要先等待日志备份操作的完成,因此如果执行该操作时数据库中还有大量未备份过的日志,则日志文件的收缩仍需要等待较久的时间才能完成。

临时文件空间

临时文件空间指的是SQL Server中的系统数据库tempdb占用的空间大小。由于tempdb库总是使用简单恢复模式,因此其日志文件增长到很大的情况是很少见的。但tempdb库的数据文件增长到很大的情况则较为常见,如大量临时表的使用、大表连接或排序操作、大量基于快照的row versioning数据等都可能导致tempdb库数据文件空间的大量使用。

查看数据库空间使用情况的命令如DBCC SHOWFILESTATS等对于tempdb库也是适用的。但是在很多情况下,即使在tempdb库中显示有大量未使用的空间,通过DBCC SHRINKFILE命令也无法有效的将其收缩到很小。并且在RDS中默认也没有授予用户直接访问tempdb库的权限,因此用户也无法直接对tempdb库执行文件收缩的操作。

因此针对tempdb库空间占用过大的情况,一方面可尽量从数据库应用层面规避,如减少不必要的临时表的使用、减少不必要的大表连接查询、避免数据库中有长事务等;另一方面就是当tempdb库增长到较大时,可以安排合适的时间对RDS实例执行一次重启操作,SQL Server服务重启之后,tempdb库会恢复到实例创建之初时的大小。

关于SQL Server中的tempdb数据库空间使用情况的监控与分析,可以参考如下链接:

https://www.mssqltips.com/sqlservertip/4356/track-sql-server-tempdb-space-usage/

系统文件空间

系统文件空间包括系统数据库master、msdb和model的所有文件,以及SQL Server实例系统目录下的一些文件,如错误日志、default trace、系统扩展事件文件等。

通常情况下,以上这些文件都不会很大,一般加在一起也不会超过几百MB。但有些情况下,SQL Server的错误日志文件大小增长到几GB甚至更大也是有可能的。

例外一种可能导致系统文件空间增长到很大的情况,就是SQL Server服务在运行过程中遇到了严重的异常时自动产生的内存转储(memory dump)文件,这通常意味着可能遇到了SQL Server产品中的bug。虽然这种问题发生的几率不高,但如果出现是有可能导致短时间内生成较多的dump文件并占用较大的磁盘空间的。

对于RDS用户来说,无法直接获知各类系统文件实际占用的磁盘空间的大小。如果在监控中发现系统文件空间使用过高的情况,可提交工单联系阿里云售后帮助检查具体的原因。

存储空间扩容

当出现RDS实例存储空间使用率过高,且参考上述说明评估后发现无法有效降低空间使用大小的情况下,应及时对实例进行存储空间的扩容。

各版本的RDS SQL Server实例在执行存储空间扩容时的操作方式都是一样的,即直接从RDS控制台上发起“变更配置”的操作,并指定扩容后存储空间大小及切换时间规则:

【巡检问题分析与最佳实践】RDS SQL Server 空间使用问题

但是由于不同版本的RDS SQL Server实例在底层架构上的差异,其存储空间扩容任务执行的机制及变配所需时间也有所不同。

  1. RDS SQL Server 2008 R2本地盘版高可用版

由于采用多实例共享同一物理主机上的本地磁盘的模式,在做存储空间扩容时,如果本地磁盘可用空间充足,则任务可在1分钟以内完成,并且不会造成任何数据库访问的中断。

但如果本地磁盘空间不能满足扩容要求的话,则会产生跨机迁移的任务,根据实例数据量大小的不同,整个任务的执行用时在20分钟到1-2天不等,其中切换时的数据库访问中断时间一般不超过30秒。

  1. RDS SQL Server 2008 R2及以上云盘版高可用版

对于云盘版实例来说,无法直接在线的完成存储空间的扩容,但是也无需在实例或主机之间进行数据的迁移。存储空间扩容任务的执行过程,是首先在备实例上将操作系统关机并进行云盘空间的快速扩容,然后启动备实例,待主备数据同步之后进行主备切换,最后在新的备实例(即原主实例)上重复同样的过程。

上述过程中的整体用时一般在10-20分钟之间,其中切换时的数据库访问中断时间一般不超过30秒。

  1. RDS SQL Server 2012及以上云盘版单机版

对于单机版实例来说,为进一步确保存储空间扩容过程中的数据可靠性,在正式开始变配任务执行前会先对实例上的数据库做一次临时备份(通常为增量备份),之后是将实例的操作系统关机并进行云盘空间的快速扩容,最后启动实例并等待数据恢复完成。

视具体情况的不同,正式开始变配操作前等待临时备份完成的时间从几分钟到几小时不等,变配过程中数据库访问中断的时间一般在几分钟到十几分钟之间。






上一篇:Android 插件化 动态升级


下一篇:RDS MySQL参数time_zone最佳实践