最近、SQL Server 2005からSQL Server 2012にアップグレードしました。SQLServer 2005では、2012のように圧縮バックアップを作成するオプションはありません。
圧縮なしで既に初期化されているファイルに対してBACKUP DATABASE ... WITH (COMPRESSION);
を試行すると、BACKUP DATABASE
コマンドは、次のエラーメッセージで失敗します。
ERROR MESSAGE : BACKUP DATABASE is terminating abnormally.
ERROR CODE : 3013
既存のバックアップファイルが圧縮バックアップ用に初期化されているかどうかを確認するにはどうすればよいですか?
データベースバックアップファイルが圧縮用に初期化されているかどうかを判断するために使用できる次のストアドプロシージャを作成しました。
CREATE PROCEDURE IsBackupFileCompressed
(
@BackupFileName nvarchar(255)
, @UseXPFileExists bit = 1
)
AS
BEGIN
/*
Inspects the header of the given backup file to see if the
file contains a SQL Server compressed backup.
Returns 1 if the backup is compressed, 0 if uncompressed.
By: Max Vernon
Date: 2013-03-26
*/
SET NOCOUNT ON;
DECLARE @FileExists bit;
DECLARE @Compressed bit;
DECLARE @cmd nvarchar(max);
DECLARE @ShellText NVARCHAR(512);
DECLARE @ShellResults TABLE (
ShellText nvarchar(255)
);
DECLARE @Exists TABLE
(
[File Exists] bit
, [File is a Directory] bit
, [Parent Directory Exists] bit
);
DECLARE @t TABLE (
BackupName nvarchar(255)
, BackupDescription nvarchar(255)
, BackupType int
, ExpirationDate datetime
, Compressed int
, Position int
, DeviceType int
, UserName nvarchar(255)
, ServerName nvarchar(255)
, DatabaseName nvarchar(255)
, DatabaseVersion int
, DatabaseCreationDate datetime
, BackupSize numeric(38,0)
, FirstLSN numeric(38,0)
, LastLSN numeric(38,0)
, CheckpointLSN numeric(38,0)
, DatabaseBackupLSN numeric(38,0)
, BackupStartDate datetime
, BackupFinishDate datetime
, SortOrder int
, CodePage int
, UnicodeLocaleId int
, UnicodeComparisonStyle int
, CompatibilityLevel int
, SoftwareVendorId int
, SoftwareVersionMajor int
, SoftwareVersionMinor int
, SoftwareVersionBuild int
, MachineName nvarchar(255)
, Flags int
, BindingID uniqueidentifier
, RecoveryForkID uniqueidentifier
, Collation nvarchar(255)
, FamilyGUID uniqueidentifier
, HasBulkLoggedData int
, IsSnapshot int
, IsReadOnly int
, IsSingleUser int
, HasBackupChecksums int
, IsDamaged int
, BeginsLogChain int
, HasIncompleteMetaData int
, IsForceOffline int
, IsCopyOnly int
, FirstRecoveryForkID uniqueidentifier
, ForkPointLSN numeric(38,0)
, RecoveryModel nvarchar(255)
, DifferentialBaseLSN numeric(38,0)
, DifferentialBaseGUID uniqueidentifier
, BackupTypeDescription nvarchar(255)
, BackupSetGUID uniqueidentifier
, CompressedBackupSize numeric(38,0)
, Containment int
);
SET @FileExists = 0;
IF @UseXPFileExists = 1
BEGIN
DECLARE @IsXPCmdShellEnabled BIT;
SET @IsXPCmdShellEnabled = CAST(
(
SELECT top(1) value_in_use
FROM sys.configurations c
WHERE c.name = 'xp_cmdshell'
) as bit);
IF @IsXPCmdShellEnabled = 1
BEGIN
SET @ShellText = 'dir /b ' + @BackupFileName
INSERT INTO @ShellResults
exec xp_cmdshell @ShellText;
SELECT @FileExists = COUNT(*)
FROM @ShellResults S
WHERE @BackupFileName LIKE ('%' + s.ShellText)
AND s.ShellText IS NOT NULL;
END
ELSE
BEGIN
/*
This is a fallback in case XP_CMDSHELL is disabled
Unfortunately, this will trigger a SEV16 error if the file does not exist,
setting off alarm bells all over the place
*/
BEGIN TRY
SET @cmd = 'RESTORE LABELONLY FROM DISK=''' + @BackupFileName + ''';';
EXEC sp_executesql @cmd;
SET @FileExists = 1;
END TRY
BEGIN CATCH
SET @FileExists = 0;
END CATCH
END
END
ELSE
BEGIN
INSERT INTO @Exists
EXEC Master.dbo.xp_fileexist @BackupFileName;
SELECT @FileExists = [File Exists] FROM @Exists E;
END
SET @Compressed = 0;
IF @FileExists > 0
BEGIN
SET @cmd = 'RESTORE HEADERONLY FROM DISK=''' + @BackupFileName + ''';';
INSERT INTO @t
EXEC sp_executesql @cmd;
SELECT @Compressed = Compressed FROM @t t;
END
SELECT @Compressed;
END
GO
このストアドプロシージャは、xp_cmdshell
が有効になっていない場合にTRY...CATCH
ブロックでxp_cmdshell
を使用するなど、さまざまな方法でファイルが存在するかどうかを確認する方法と、優先するメソッドxp_fileexists
を示します。
私はこのストアドプロシージャのしくみに信じられないほど満足していません。もっと軽量なバージョンを好むでしょう。
同じファイルに何度もバックアップするのではなく、WITH INIT
と新しいファイルを常に使用することを検討してください。ファイル名に独自のタイムスタンプが埋め込まれている複数のバックアップファイルを管理し、各ファイルを個別にアーカイブ/パージする方が簡単だと思います。同じファイルにバックアップをダンプし続けると、ますます大きくなり、IMHOの管理が難しくなります。あなたはもう気にする必要がないことを気にしないでください
また、なぜバックアップの圧縮をオンまたはオフにするのか、よくわかりません。無効にした方がよいケースを見つけましたか?圧縮をサポートするエディションで、圧縮なしで1回限りのバックアップを作成し、同じファイルを使用する実際の使用例はありますか?どうして?
とにかく、あなたはいつも次のような非常に簡単なことをすることができます:
BEGIN TRY
BACKUP DATABASE x TO DISK = 'c:\wherever\x.bak' WITH COMPRESSION, ...;
END TRY
BEGIN CATCH
BACKUP DATABASE x TO DISK = 'c:\wherever\x.bak', ...;
END CATCH
作業が完了する直前にエラーが発生します。
ただし、そもそも同じファイルを何度も使用しない方がずっと良いと私は思います。私見では。
同じことを行うのに便利なpowershell関数を次に示します。
Function IsBackupCompressed
{
Param
(
[string]$Server,
[string]$BAKFile
)
[Void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SQLServer.SMO')
[Void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SQLServer.SMOExtended')
$SMOServer = New-Object Microsoft.SqlServer.Management.Smo.Server $Server
$Res = New-Object Microsoft.SqlServer.Management.Smo.Restore
$Res.Devices.AddDevice($BAKFile, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
$Res.ReadBackupHeader($SMOServer).Rows[0].Compressed
}
サーバー名と.BAKファイルへのパスを渡すと、圧縮のために1または0が返されます。
.BAKファイルのパスは、スクリプトを実行する場所からの相対パスである必要があることに注意してください。
これが本番環境に入る場合は、ファイルが存在しないなどのエラートラップを追加する必要があります。
特定のデータベースバックアップファイルが圧縮を使用してバックアップされたかどうかを確認するには、ファイルのヘッダー情報にエラーを挿入できます。
RESTORE HEADERONLY FROM DISK = 'Path to backup file';
返される列の1つに「圧縮済み」というラベルが付いています。 1 =圧縮、0 =圧縮しない。
ファイルを再利用できるかどうか、またはファイルを再初期化する必要があるかどうかについて制御フローが必要な場合は、その情報を一時テーブルにロードできます。何かのようなもの:
DECLARE @RestoreHeader TABLE (
BackupName NVARCHAR(128),
BackupDescription NVARCHAR(255),
BackupType SMALLINT,
ExpirationDate DATETIME,
Compressed BIT,
Position SMALLINT,
DeviceType TINYINT,
UserName NVARCHAR(128),
ServerName NVARCHAR(128),
DatabaseName NVARCHAR(128),
DatabaseVersion INT,
DatabaseCreationDate DATETIME,
BackupSize NUMERIC(20,0),
FirstLSN NUMERIC(25,0),
LastLSN NUMERIC(25,0),
CheckpointLSN NUMERIC(25,0),
DatabaseBackupLSN NUMERIC(25,0),
BackupStartDate DATETIME,
BackupFinishDate DATETIME,
SortOrder SMALLINT,
CodePage SMALLINT,
UnicodeLocaleId INT,
UnicodeComparisonStyle INT,
CompatibilityLevel TINYINT,
SoftwareVendorId INT,
SoftwareVersionMajor INT,
SoftwareVersionMinor INT,
SoftwareVersionBuild INT,
MachineName NVARCHAR(128),
Flags INT,
BindingID UNIQUEIDENTIFIER,
RecoveryForkID UNIQUEIDENTIFIER,
Collation NVARCHAR(128),
FamilyGUID UNIQUEIDENTIFIER,
HasBulkLoggedData BIT,
IsSnapshot BIT,
IsReadOnly BIT,
IsSingleUser BIT,
HasBackupChecksums BIT,
IsDamaged BIT,
BeginsLogChain BIT,
HasIncompleteMetaData BIT,
IsForceOffline BIT,
IsCopyOnly BIT,
FirstRecoveryForkID UNIQUEIDENTIFIER,
ForkPointLSN NUMERIC(25,0) NULL,
RecoveryModel NVARCHAR(60),
DifferentialBaseLSN NUMERIC(25,0) NULL,
DifferentialBaseGUID UNIQUEIDENTIFIER,
BackupTypeDescription NVARCHAR(60),
BackupSetGUID UNIQUEIDENTIFIER NULL,
CompressedBackupSize BIGINT,
containment TINYINT NOT NULL
);
INSERT INTO @RestoreHeader
EXEC ('RESTORE HEADERONLY FROM DISK = ''Path to backup file''');
SELECT Compressed FROM @RestoreHeader
以下があなたに役立つかどうかはわかりませんが(多くの素晴らしい答えがあったため)、バックアップ履歴にアクセスできる場合は、次のようなクエリで以前のバックアップが圧縮されているかどうかを判断できると思います。
select top(10) database_name,
case
when backup_size = compressed_backup_size then 'Compressed'
else 'Not compressed'
end as Compression,
backup_finish_date
from msdb.dbo.backupset
where database_name ='myDB'
order by backup_start_date desc