在談到SQL Server的高可用性之前,我們首先要談一談單實例的高可用性。在單實例的高可用性中,不可忽略的就是文件和文件組的高可用性。SQL Server允許在某些文件損壞或離線的情況下,允許數據庫依然保持部分在線,從而保證了高可用性。
文件和文件組
有關文件和文件組的基本概念,有很多文章已經闡述過了。這里我只是提一下,文件組作為SQL Server訪問文件的一個抽象層而存在。因此SQL Server上所做的操作不是直接針對文件,而是針對文件組。
使用多個文件組和文件不僅僅是為了分散IO和提高性能,還有高可用性方面的原因。有關一個數據庫應該包含幾個文件或文件組,Paul Randal已經做過非常棒的闡述,請參閱:http://www.sqlskills.com/blogs/paul/files-and-filegroups-survey-results/。
數據庫中使用多個文件或文件組在高可用性方面的好處包括:
- 某文件的IO損壞,數據庫還可以保證部分在線。
- 將索引和表分開存放,假如索引文件不在線,數據依然可以被訪問。
- 歷史數據和熱數據分開,歷史歸檔數據損壞,不影響熱數據。
- 分開數據文件使得在災難恢復時僅僅恢復部分數據從而縮短了宕機時間
- 數據庫分為多個文件使得可以通過增加文件或移動文件的方式解決空間不足的問題
文件
在SQL Server中,文件分為三類,分別為:
- 主數據文件
- 輔助數據文件
- 日志文件
其中,主數據文件默認以擴展名mdf結尾,輔助數據庫文件默認以ndf結尾,日志文件以ldf結尾。雖然擴展名是可以修改的,但強烈建議不要去改擴展名。
上面提到文件名值得是物理文件名,但是實際上在SQL Server中進行操作,操作的是邏輯文件名。
任何時間,文件都會處于某一種狀態,這些狀態包括:
- 在線
- 離線
- 恢復中
- 還原掛起
- 質疑
可以通過sys.database_files這個DMV來查看數據庫文件中包含狀態在內的相關信息,如圖1所示。
圖1.查看數據庫中文件的狀態等相關信息
你甚至可以在數據庫缺少NDF文件時附加數據庫,具體細節,請參閱MCM黃大師的一篇文章:http://www.sqlnotes.info/2013/05/07/attach-database-with-missing-ndf-file/。
文件組
在SQL Server中,文件組中某個文件的狀態決定了整個文件組的狀態。但文件的狀態獨立于數據庫的狀態,比如說文件的狀態是離線,但數據庫依然能保證在線,這也就是所謂的數據庫部分在線,舉個例子,某個文件包含了名為selldata的表,如果該文件離線,但數據庫在線,所有針對該selldata的表上的操作都會失敗。
如果需要數據庫中的某個文件組在線,該文件組中的所有文件都應該處于在線狀態。
表分區
表分區是自SQL Server 2005之后出現的一個概念,我之前已經寫過一篇關于表分區的文章。表分區的概念雖然很老了,但是很多地方對于表分區的使用依然處于非常初級的階段。
我見過大部分想到使用表分區的例子是出現性能問題,從而考慮分散大表的IO。但實際上,表分區還會提高可用性。使用表分區的好處還包括:
- 輕松管理大表或分區
- 提高并發性(產生分區鎖,而不是表鎖)
- 以文件組級別就行備份和還原,從而僅僅只備份和還原表的一部分(比如說只備份表中的熱數據),從而減少了還原時間
- 可以僅僅在線重建某個分區
值得注意的是,對表分區后,也要對表上的非聚集索引進行索引分區。否則有可能造成性能方面的例子。
DEMO
DEMO1 :僅重建某個分區
下面例子是一個簡單的分區表,并對索引進行分區后,僅僅重建某個分區,而不是整個索引。比如說表中按照數據冷熱進行分區,可以僅僅對熱數據進行重建,從而大大減少了重建索引所需的時間,如代碼清單1所示。
--創建分區函數 CREATE PARTITION FUNCTION [t](int) AS RANGE LEFT FOR VALUES (100, 500) --分區架構 CREATE PARTITION SCHEME [x] AS PARTITION [t] TO ([PRIMARY], [FileGroup1], [FileGroup1]) --創建表 CREATE TABLE [Sales].[SalesOrderDetailPartition]( [SalesOrderID] [int] NOT NULL, [SalesOrderDetailID] [int] IDENTITY(1,1) NOT NULL, [CarrierTrackingNumber] [nvarchar](25) NULL, [OrderQty] [smallint] NOT NULL, [ProductID] [int] NOT NULL, [SpecialOfferID] [int] NOT NULL, [UnitPrice] [money] NOT NULL, [UnitPriceDiscount] [money] NOT NULL, [LineTotal] AS (isnull(([UnitPrice]*((1.0)-[UnitPriceDiscount]))*[OrderQty],(0.0))), [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, [ModifiedDate] [datetime] NOT NULL, ) ON x(SalesOrderID) INSERT INTO [Sales].[SalesOrderDetailPartition]([SalesOrderID], [CarrierTrackingNumber], [OrderQty] , [ProductID] , [SpecialOfferID], [UnitPrice], [UnitPriceDiscount],ModifiedDate,rowguid) SELECT [SalesOrderID], [CarrierTrackingNumber], [OrderQty] , [ProductID] , [SpecialOfferID], [UnitPrice], [UnitPriceDiscount],ModifiedDate,rowguid FROM [Sales].[SalesOrderDetail] go --創建索引分區 CREATE NONCLUSTERED INDEX test_partition_idx ON [Sales].[SalesOrderDetailPartition](ProductID) on x(SalesOrderID) --僅僅重建某個分區 ALTER INDEX test_partition_idx ON [Sales].[SalesOrderDetailPartition] REBUILD Partition = 1
代碼清單1.僅僅重建某個分區,而不是整個索引
關于這里,更深入的文章可以參閱:http://www.mssqltips.com/sqlservertip/1621/sql-server-partitioned-tables-with-multiple-filegroups-for-high-availability/
DEMO2:數據庫部分在線和文件還原
--創建測試數據庫 CREATE DATABASE test GO --改成完整恢復模式 ALTER DATABASE test SET RECOVERY FULL --添加一個文件組 ALTER DATABASE test ADD FILEGROUP WW_GROUP GO --向文件組中添加文件 ALTER DATABASE test ADD FILE ( NAME = ww, FILENAME = 'D:\wwdat1.ndf', SIZE = 5MB, MAXSIZE = 100MB, FILEGROWTH = 5MB) TO FILEGROUP ww_Group --在不同文件組上分別創建兩個表 CREATE TABLE test..test ( id INT IDENTITY ) ON [primary] CREATE TABLE test..test_GR ( id INT IDENTITY ) ON ww_Group --做完整備份 BACKUP DATABASE test TO DISK='D:\Test_backup.bak'WITH INIT --做文件備份 BACKUP DATABASE test FILE = 'ww', FILEGROUP = 'ww_Group' TO DISK='D:\CROUPFILES.bak'WITH INIT --備份日志 BACKUP LOG test TO DISK='D:\Test__log.ldf'WITH INIT --刪除文件組中的表內的數據 TRUNCATE TABLE test..test_GR --還原備份,日志僅僅被應用于那個還原狀態的文件 RESTORE DATABASE test FILE = 'ww', FILEGROUP = 'ww_Group' FROM DISK ='D:\CROUPFILES.bak' WITH FILE = 1,NORECOVERY RESTORE LOG test FROM DISK='D:\Test__log.ldf' WITH FILE = 1, NORECOVERY --備份尾端日志 BACKUP LOG test TO DISK='D:\Test__log.ldf' WITH NOINIT,NO_TRUNCATE --還原尾端日志 RESTORE LOG test FROM DISK='D:\Test__log.ldf' WITH FILE = 2, RECOVERY GO --查看數據,刪除數據的操作被成功恢復 SELECT * FROM test..test_GR --清除數據庫 DROP DATABASE test
代碼清單2.備份還原單個文件
代碼清單2很好的闡述了整個文件備份還原的過程,其中,在文件還原的過程中我們可以看到數據庫本身是在線的,但數據庫中有一個文件處于還原狀態,如圖2所示。
圖2.ww文件處于還原中狀態
此時對于表test_GR做操作的話,會提示因文件組沒有聯機而失敗,如圖3所示。
圖3.因為文件組沒有聯機而導致操作失敗
再對尾端日志進行備份還原之后,該文件組成功上線。
小結
本篇文章闡述了文件和文件組在高可用性中的作用。了解這些特性對于降低還原時間非常有必要。在數據庫開始上線之前,盡量合理的把一個數據庫分為多個文件組和文件,不僅僅提升性能和并發性,還可以使得DR更加容易。
文章列表