摘要: 摘要 在SQL Server备份专题分享中,前四期我们分享了:三种常见的数据库备份、备份策略的制定、如何查找备份链以及数据库的三种恢复模式与备份之间的关系。本次月报我们分享SQL Server如何利用文件组技术来实现数据库冷热数据隔离备份的方案。
摘要
在SQL Server备份专题分享中,前四期我们分享了:三种常见的数据库备份、备份策略的制定、如何查找备份链以及数据库的三种恢复模式与备份之间的关系。本次月报我们分享SQL Server如何利用文件组技术来实现数据库冷热数据隔离备份的方案。
场景引入
假设某公司有一个非常重要的超大的数据库(超过10TB),面临如下场景:
- 该数据库中存储了近10年的用户支付信息(payment),非常重要
- 每年的数据归档存储在年表中,历史年表中的数据只读不写(历史payment信息无需再修改),只有当前年表数据既读又写
- 每次数据库全备耗时太长,超过20小时;数据库还原操作耗时更长,超过30小时
如何优化设计这个数据库以及备份恢复系统,可以使得备份、还原更加高效?
文件组简介
文件组的详细介绍不是本次分享的重点,但是作为本文介绍的核心技术,有必要对其优点、创建以及使用方法来简单介绍SQL Server中的文件组。
使用文件组的优点
SQL Server支持将表、索引数据存放到非Primary文件组,这样当数据库拥有多个文件组时就具备了如下好处:
- 分散I/O压力到不同的文件组上,如果不同文件组的文件位于不同的磁盘的话,可以分散磁盘压力。
- 针对不同的文件组进行DBCC CHECKFILEGROUP操作,并且同一个数据库可以多个进程并行处理,减少大数据维护时间。
- 可以针对文件组级别进行备份和还原操作,更细粒度控制备份和还原策略。
创建数据库时创建文件组
我们可以在创建数据库时直接创建文件组,代码如下:
USE master GO EXEC sys.xp_create_subdir 'C:\SQLServer\Data\' EXEC sys.xp_create_subdir 'C:\SQLServer\Logs\' CREATE DATABASE [TestFG] ON PRIMARY ( NAME = N'TestFG', FILENAME = N'C:\SQLServer\Data\TestFG.mdf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FG2010] ( NAME = N'FG2010', FILENAME = N'C:\SQLServer\Data\FG2010.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FG2011] ( NAME = N'FG2011', FILENAME = N'C:\SQLServer\Data\FG2011.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FG2012] ( NAME = N'FG2012', FILENAME = N'C:\SQLServer\Data\FG2012.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ) LOG ON ( NAME = N'TestFG_log', FILENAME = N'C:\SQLServer\Logs\TestFG_log.ldf' , SIZE = 5MB , FILEGROWTH = 50MB) GO
注意: 为了保证数据库文件组I/O的负载均衡能力,请将所有文件的初始大小和自动增长参数保持一致,以保证轮询调度分配算法正常工作。
单独创建创建组
如果数据库已经存在,我们也同样有能力添加文件组,代码如下:
--Add filegroup FG2013 USE master GO ALTERDATABASE [TestFG] ADD FILEGROUP [FG2013]; -- Add data file to FG2013ALTERDATABASE [TestFG] ADD FILE (NAME = FG2013, SIZE = 5MB , FILEGROWTH = 50MB ,FILENAME = N'C:\SQLServer\Data\FG2013.ndf') TO FILEGROUP [FG2013] GO USE [TestFG] GOSELECT * FROM sys.filegroups
最终文件组信息,展示如下:
使用文件组
文件组创建完毕后,我们可以将表和索引放到对应的文件组。比如: 将聚集索引放到PRIMARY文件组;表和索引数据放到FG2010文件组,代码如下:
USE [TestFG] GO CREATETABLE [dbo].[Orders_2010]( [OrderID] [int] IDENTITY(1,1) NOTNULL, [OrderDate] [datetime] NULL, CONSTRAINT [PK_Orders_2010] PRIMARYKEY CLUSTERED ( [OrderID] ASC ) ON [PRIMARY] ) ON [FG2010] GOCREATE NONCLUSTERED INDEX IX_OrderDate ON [dbo].[Orders_2010] (OrderDate) ON [FG2010];
方案设计
文件组的基本知识点介绍完毕后,根据场景引入中的内容,我们将利用SQL Server文件组技术来实现冷热数据隔离备份的方案设计介绍如下。
设计分析
由于payment数据库过大,超过10TB,单次全量备份超过20小时,如果按照常规的完全备份,会导致备份文件过大、耗时过长、甚至会因为备份操作对I/O能力的消耗影响到正常业务。我们仔细想想会发现,虽然数据库本身很大,但是,由于只有当前年表数据会不断变化(热数据),历史年表数据不会修改(冷数据),因此正真有数据变化操作的数据量相对整个库来看并不大。那么,我们将数据库设计为历史年表数据放到Read only的文件组上,把当前年表数据放到Read write的文件组上,备份系统仅仅需要备份Primary和当前年表所在的文件组即可(当然首次还是需要对数据库做一次性完整备份的)。这样既可以大大节约备份对I/O能力的消耗,又实现了冷热数据的隔离备份操作,还达到了分散了文件的I/O压力,最终达到数据库设计和备份系统优化的目的,可谓一箭多雕。
以上文字分析,画一个漂亮的设计图出来,直观展示如下:
设计图说明
以下对设计图做详细说明,以便对设计方案有更加直观和深入理解。 整个数据库包含13个文件,包括:
- 1个主文件组(Primary File Group):用户存放数据库系统表、视图等对象信息,文件组可读可写。
- 10个用户自定义只读文件组(User-defined Read Only File Group):用于存放历史年表的数据及相应索引数据,每一年的数据存放到一个文件组中。
- 1个用户自定义可读写文件组(User-defined Read Write File Group):用于存放当前年表数据和相应索引数据,该表数据必须可读可写,所以文件组必须可读可写。
- 1个数据库事务日志文件:用于数据库事务日志,我们需要定期备份数据库事务日志。
方案实现
设计方案完成以后,接下来就是方案的集体实现了,具体实现包括:
- 创建数据库
- 创建年表
- 文件组设置
- 冷热备份实现
创建数据库
创建数据库的同时,我们创建了Primary文件组和2008 ~ 2017的文件组,这里需要特别提醒,请务必保证所有文件组中文件的初始大小和增长量相同,代码如下:
USE master GO EXEC sys.xp_create_subdir 'C:\DATA\Payment\Data\' EXEC sys.xp_create_subdir 'C:\DATA\Payment\Log\' CREATE DATABASE [Payment] ON PRIMARY ( NAME = N'Payment', FILENAME = N'C:\DATA\Payment\Data\Payment.mdf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2008] ( NAME = N'FGPayment2008', FILENAME = N'C:\DATA\Payment\Data\Payment_2008.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2009] ( NAME = N'FGPayment2009', FILENAME = N'C:\DATA\Payment\Data\Payment_2009.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2010] ( NAME = N'FGPayment2010', FILENAME = N'C:\DATA\Payment\Data\Payment_2010.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2011] ( NAME = N'FGPayment2011', FILENAME = N'C:\DATA\Payment\Data\Payment_2011.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2012] ( NAME = N'FGPayment2012', FILENAME = N'C:\DATA\Payment\Data\Payment_2012.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2013] ( NAME = N'FGPayment2013', FILENAME = N'C:\DATA\Payment\Data\Payment_2013.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2014] ( NAME = N'FGPayment2014', FILENAME = N'C:\DATA\Payment\Data\Payment_2014.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2015] ( NAME = N'FGPayment2015', FILENAME = N'C:\DATA\Payment\Data\Payment_2015.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2016] ( NAME = N'FGPayment2016', FILENAME = N'C:\DATA\Payment\Data\Payment_2016.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ), FILEGROUP [FGPayment2017] ( NAME = N'FGPayment2017', FILENAME = N'C:\DATA\Payment\Data\Payment_2017.ndf' , SIZE = 5MB ,FILEGROWTH = 50MB ) LOG ON ( NAME = N'Payment_log', FILENAME = N'C:\DATA\Payment\Log\Payment_log.ldf' , SIZE = 5MB , FILEGROWTH = 50MB) GO
考虑到每年我们都要添加新的文件组到数据库中,因此2018年的文件组单独创建如下:
--Add filegroup FGPayment2018 USE master GO ALTERDATABASE [Payment] ADD FILEGROUP [FGPayment2018]; -- Add data file to FGPayment2018ALTERDATABASE [Payment] ADD FILE (NAME = FGPayment2018, SIZE = 5MB , FILEGROWTH = 50MB ,FILENAME = N'C:\DATA\Payment\Data\Payment_2018.ndf') TO FILEGROUP [FGPayment2018] GO
最终再次确认数据库文件组信息,代码如下:
USE [Payment] GO SELECT file_name = mf.name, filegroup_name = fg.name, mf.physical_name,mf.size,mf.growth FROM sys.master_files AS mf INNERJOIN sys.filegroups as fg ON mf.data_space_id = fg.data_space_id WHERE mf.database_id = db_id('Payment') ORDERBY mf.type;
结果展示如下图所示:
创建年表
数据库以及相应文件组创建完毕后,接下来我们创建对应的年表并插入一些测试数据,如下:
USE [Payment] GO CREATETABLE [dbo].[Payment_2008]( [Payment_ID] [bigint] IDENTITY(12008,100) NOTNULL, [OrderID] [bigint] NOTNULL, CONSTRAINT [PK_Payment_2008] PRIMARYKEY CLUSTERED ( [Payment_ID] ASC ) ON [FGPayment2008] ) ON [FGPayment2008] GOCREATE NONCLUSTERED INDEX IX_OrderID ON [dbo].[Payment_2008] ([OrderID]) ON [FGPayment2008]; CREATETABLE [dbo].[Payment_2009]( [Payment_ID] [bigint] IDENTITY(12009,100) NOTNULL, [OrderID] [bigint] NOTNULL, CONSTRAINT [PK_Payment_2009] PRIMARYKEY CLUSTERED ( [Payment_ID] ASC ) ON [FGPayment2009] ) ON [FGPayment2009] GOCREATE NONCLUSTERED INDEX IX_OrderID ON [dbo].[Payment_2009] ([OrderID]) ON [FGPayment2009]; --这里省略了2010-2017的表创建,请参照以上建表和索引代码,自行补充CREATETABLE [dbo].[Payment_2018]( [Payment_ID] [bigint] IDENTITY(12018,100) NOTNULL, [OrderID] [bigint] NOTNULL, CONSTRAINT [PK_Payment_2018] PRIMARYKEY CLUSTERED ( [Payment_ID] ASC ) ON [FGPayment2018] ) ON [FGPayment2018] GOCREATE NONCLUSTERED INDEX IX_OrderID ON [dbo].[Payment_2018] ([OrderID]) ON [FGPayment2018];
这里需要特别提醒两点:
- 限于篇幅,建表代码中省略了2010 - 2017表创建,请自行补充
- 每个年表的Payment_ID字段初始值是不一样的,以免查询所有payment信息该字段值存在重复的情况
其次,我们检查所有年表的文件组分布情况如下:
USE [Payment] GO SELECT table_name = tb.[name], index_name = ix.[name], located_filegroup_name = fg.[name] FROM sys.indexes ix INNERJOIN sys.filegroups fg ON ix.data_space_id = fg.data_space_id INNERJOIN sys.tables tb ON ix.[object_id] = tb.[object_id] WHERE ix.data_space_id = fg.data_space_id GO
查询结果截取其中部分如下,我们看到所有年表及索引都按照我们的预期分布到对应的文件组上去了。
最后,为了测试,我们在对应年表中放入一些数据:
USE [Payment] GO SET NOCOUNT ONINSERTINTO [Payment_2008] SELECT2008; INSERTINTO [Payment_2009] SELECT2009; --省略掉2010 - 2017,自行补充INSERTINTO [Payment_2018] SELECT2018;
文件组设置
年表创建完完毕、测试数据初始化完成后,接下来,我们做文件组读写属性的设置,代码如下:
USE master GO ALTERDATABASE [Payment] MODIFY FILEGROUP [FGPayment2008] READ_ONLY; ALTERDATABASE [Payment] MODIFY FILEGROUP [FGPayment2009] READ_ONLY; --这里省略了2010 - 2017文件组read only属性的设置,请自行补充ALTERDATABASE [Payment] MODIFY FILEGROUP [FGPayment2018] READ_WRITE;
最终我们的文件组读写属性如下:
USE [Payment] GO SELECT name, is_default, is_read_only FROM sys.filegroups GO
截图如下:
冷热备份实现
所有文件组创建成功,并且读写属性配置完毕后,我们需要对数据库可读写文件组进行全量备份、差异备份和数据库级别的日志备份,为了方便测试,我们会在两次备份之间插入一条数据。备份操作的大体思路是:
- 首先,对整个数据库进行一次性全量备份
- 其次,对可读写文件组进行周期性全量备份
- 接下来,对可读写文件组进行周期性差异备份
- 最后,对整个数据库进行周期性事务日志备份
--Take a one time full backup of payment database USE [master]; GO BACKUP DATABASE [Payment] TO DISK = N'C:\DATA\Payment\BACKUP\Payment_20180316_full.bak'WITH COMPRESSION, Stats=5 ; GO -- for testing, init one record USE [Payment]; GO INSERT INTO [dbo].[Payment_2018] SELECT201801; GO --Take a full backup foreach writable filegoup (just backup FGPayment2018 as an example) BACKUP DATABASE [Payment] FILEGROUP = 'FGPayment2018'TO DISK = 'C:\DATA\Payment\BACKUP\Payment_FGPayment2018_20180316_full.bak'WITH COMPRESSION, Stats=5 ; GO -- for testing, insert one record INSERT INTO [dbo].[Payment_2018] SELECT201802; GO --Take a differential backup foreach writable filegoup (just backup FGPayment2018 as an example) BACKUP DATABASE [Payment] FILEGROUP = N'FGPayment2018'TO DISK = N'C:\DATA\Payment\BACKUP\Payment_FGPayment2018_20180316_diff.bak'WITH DIFFERENTIAL, COMPRESSION, Stats=5 ; GO -- for testing, insert one record INSERT INTO [dbo].[Payment_2018] SELECT201803; GO -- Take a transaction log backup of database payment BACKUP LOG [Payment] TO DISK = 'C:\DATA\Payment\BACKUP\Payment_20180316_log.trn'; GO
这样备份的好处是,我们只需要对可读写的文件组(FGPayment2018)进行完整和差异备份(Primary中包含系统对象,变化很小,实际场景中,Primary文件组也需要备份),而其他的9个只读文件组无需备份,因为数据不会再变化。如此,我们就实现了冷热数据隔离备份的方案。 接下来的一个问题是,万一Payment数据发生灾难,导致数据损失,我们如何从备份集中将数据库恢复出来呢?我们可以按照如下思路来恢复备份集:
- 首先,还原整个数据库的一次性全量备份
- 其次,还原所有可读写文件组最后一个全量备份
- 接下来,还原可读写文件组最后一个差异备份
- 最后,还原整个数据库的所有事务日志备份
-- We restore full backup USE master GO RESTORE DATABASE [Payment_Dev] FROM DISK=N'C:\DATA\Payment\BACKUP\Payment_20180316_full.bak' WITH MOVE 'Payment' TO 'C:\DATA\Payment_Dev\Data\Payment_dev.mdf', MOVE 'FGPayment2008' TO 'C:\DATA\Payment_Dev\Data\FGPayment2008_dev.ndf', MOVE 'FGPayment2009' TO 'C:\DATA\Payment_Dev\Data\FGPayment2009_dev.ndf', MOVE 'FGPayment2010' TO 'C:\DATA\Payment_Dev\Data\FGPayment2010_dev.ndf', MOVE 'FGPayment2011' TO 'C:\DATA\Payment_Dev\Data\FGPayment2011_dev.ndf', MOVE 'FGPayment2012' TO 'C:\DATA\Payment_Dev\Data\FGPayment2012_dev.ndf', MOVE 'FGPayment2013' TO 'C:\DATA\Payment_Dev\Data\FGPayment2013_dev.ndf', MOVE 'FGPayment2014' TO 'C:\DATA\Payment_Dev\Data\FGPayment2014_dev.ndf', MOVE 'FGPayment2015' TO 'C:\DATA\Payment_Dev\Data\FGPayment2015_dev.ndf', MOVE 'FGPayment2016' TO 'C:\DATA\Payment_Dev\Data\FGPayment2016_dev.ndf', MOVE 'FGPayment2017' TO 'C:\DATA\Payment_Dev\Data\FGPayment2017_dev.ndf', MOVE 'FGPayment2018' TO 'C:\DATA\Payment_Dev\Data\FGPayment2018_dev.ndf', MOVE 'Payment_log' TO 'C:\DATA\Payment_Dev\Log\Payment_dev_log.ldf', NORECOVERY,STATS=5; GO -- restore writable filegroup full backup RESTORE DATABASE [Payment_Dev] FILEGROUP = N'FGPayment2018' FROM DISK = N'C:\DATA\Payment\BACKUP\Payment_FGPayment2018_20180316_full.bak' WITH NORECOVERY,STATS=5; GO -- restore writable filegroup differential backup RESTORE DATABASE [Payment_Dev] FILEGROUP = N'FGPayment2018' FROM DISK = N'C:\DATA\Payment\BACKUP\Payment_FGPayment2018_20180316_diff.bak' WITH NORECOVERY,STATS=5; GO -- restore payment database transaction log backup RESTORE LOG [Payment_Dev] FROM DISK = N'C:\DATA\Payment\BACKUP\\Payment_20180316_log.trn' WITH NORECOVERY; GO -- Take database oneline to check RESTORE DATABASE [Payment_Dev] WITH RECOVERY; GO
最后检查数据还原的结果,按照我们插入的测试数据,应该会有四条记录。
USE [Payment_Dev] GO SELECT * FROM [dbo].[Payment_2018] WITH(NOLOCK)
展示执行结果,有四条结果集,符合我们的预期,截图如下:
最后总结
本篇月报分享了如何利用SQL Server文件组技术来实现和优化冷热数据隔离备份的方案,在大大提升数据库备份还原效率的同时,还提供了I/O资源的负载均衡,提升和优化了整个数据库的性能。
阅读更多干货好文,请关注扫描以下二维码:
相关推荐
标题中的“MSSQL异地备份工具”指的是一个专门用于Microsoft SQL Server数据库的备份解决方案,它具备在不同地理位置进行数据备份的能力。这样的工具对于确保数据安全和业务连续性至关重要,特别是对于那些有多处...
4. **安全最佳实践**: - **保持更新**:定期更新SQL Server到最新版本,修复已知的安全漏洞。 - **最小权限原则**:确保数据库用户只有完成其任务所需的最低权限。 - **输入验证**:对所有用户输入进行严格的...
在本文中,我们将深入探讨如何利用MSSQL的命令行工具创建备份脚本,并通过Windows的计划任务实现定期自动备份。 标题中的“MSSQL备份脚本”指的是使用T-SQL(Transact-SQL)语言编写的一段程序,该程序能够调用...
本文将深入探讨“MSsql 数据库备份恢复源码”这一主题,以及如何利用它来确保数据的完整性和可用性。 MS SQL Server(Microsoft Structured Query Language Server)是由微软公司开发的一款关系型数据库管理系统,...
在提供的文件列表中,“autobakup.exe”可能是实现自动备份的可执行程序,它读取“default.ini”配置文件,执行备份操作,复制备份文件,并根据设定删除旧备份。使用这样的工具可以简化数据库管理,但同时也需要了解...
用于备份MSSQL数据库的工具软件,可按指定的计划备份MSSQL数据库,并将备份后的文件下载到本地。 该程序是站长必备工具。主要解决个人站长无法定时备份数据库的问题。 个人站长所使用的 MSSql 数据库服务器上一般都...
在ASP备份MSSQL数据库程序中,开发者利用ASP的内置功能和对象,如Response和Request,以及可能的ADODB库(ActiveX Data Objects),来与MSSQL数据库进行交互,执行备份任务。 MSSQL,全称Microsoft SQL Server,是...
### MSSQL数据库自动备份知识点详解 #### 一、引言 在现代企业的信息化管理中,数据的...企业在实施过程中应结合自身需求制定合理的备份方案,同时注意定期检查备份的有效性和完整性,确保能够在必要时快速恢复数据。
9. **压缩和加密**:除了直接备份到文件,还可以选择将备份文件压缩或加密,提高数据安全性。 10. **恢复备份**:备份的意义在于能够恢复数据。了解如何使用C#恢复备份同样重要,这通常涉及到Restore类的使用。 总...
"mssql 生成.sql文件"这一话题聚焦于如何从MSSQL数据库中导出数据或结构为SQL脚本文件,即.sql文件。这个过程在数据库备份、迁移、版本控制或者分享数据库设计时非常有用。 首先,我们来理解.sql文件的作用。一个....
MSSQL差异备份作为一种高效的数据保护策略,通过仅备份自上次完整备份以来发生变更的数据,有效降低了备份对系统资源的占用,同时保证了数据的完整性和可用性。对于数据库管理员而言,理解并合理运用差异备份机制,...
SQL Server 的复制技术是一种强大的数据同步解决方案,它允许数据库之间的数据和对象在不同地点间进行复制和分发,并确保数据的一致性。这项技术在分布式环境中尤其重要,用于数据分发、提高应用性能、物理隔离数据...
在数据库出现故障或者数据丢失的情况下,可以迅速地根据备份文件恢复数据,将业务中断的时间降到最低。自动启动和启动最小化的设计使得工具在后台安静运行,不影响用户正常工作,同时任务栏隐藏则保持了桌面的整洁。...
### 利用MSSQL的OPENDATASOURCE把文本文件中的数据插入、更新到ORACLE 在跨数据库操作中,经常会遇到需要将一个数据库的数据导入到另一个数据库的情况。例如,将文本文件中的数据导入到Oracle数据库中进行处理。...
td定时备份,td定时数据备份,文件定时备份,testdirector定时备份,testdirector定时数据备份,testdirector备份工具,文件备份工具,testdirector定时备份工具,文件定时备份工具。 【要求】:操作系统必须安装...
它可以有多个发布,每个发布包含一组逻辑相关数据。发布服务器会跟踪事务复制期间的数据变更,并维护所有发布的相关信息。 2. **订阅服务器**:订阅服务器是接收复制数据的服务器。它们可以订阅特定的发布,而不是...
总之,一个简单的MSSQL数据库备份恢复类会利用SQL Server提供的API或COM接口,结合适当的备份和恢复策略,实现数据库的备份与恢复。这涉及到对备份类型的理解,备份文件的管理,以及对恢复模式的掌握。在实际应用中...
"易特SQL SERVER自动备份工具"是一款专门针对MSSQL数据库设计的自动化备份解决方案。这类工具通常包含以下功能: 1. **定时备份**:用户可以设置计划任务,让备份过程在特定时间自动执行,如每天、每周或每月的固定...
本篇文章将详细探讨如何在MSSQL中将数据库内的数据转换为SQL语句文本文件,以便于数据备份、迁移或分析。 首先,我们需要理解为什么要将数据库数据转化为SQL插入语句。这种操作通常在以下几种情况下非常有用: 1. ...
MSSQL日志清理软件可以删除日志,可以备份数据库,如果备份数据库失败,确认sa是否有读写文件的权限,没有权限请先手动创建一个目录。备份数据库最好到数据库实体机上备份,若要远程备份请先在服务器上建好对应的...