web-dev-qa-db-ja.com

SQL Serverバックアップが圧縮されているかどうかを確認するにはどうすればよいですか?

最近、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

既存のバックアップファイルが圧縮バックアップ用に初期化されているかどうかを確認するにはどうすればよいですか?

5
Max Vernon

データベースバックアップファイルが圧縮用に初期化されているかどうかを判断するために使用できる次のストアドプロシージャを作成しました。

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を示します。

私はこのストアドプロシージャのしくみに信じられないほど満足していません。もっと軽量なバージョンを好むでしょう。

5
Max Vernon

同じファイルに何度もバックアップするのではなく、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

作業が完了する直前にエラーが発生します。

ただし、そもそも同じファイルを何度も使用しない方がずっと良いと私は思います。私見では。

7
Aaron Bertrand

同じことを行うのに便利な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ファイルのパスは、スクリプトを実行する場所からの相対パスである必要があることに注意してください。

これが本番環境に入る場合は、ファイルが存在しないなどのエラートラップを追加する必要があります。

6
JNK

特定のデータベースバックアップファイルが圧縮を使用してバックアップされたかどうかを確認するには、ファイルのヘッダー情報にエラーを挿入できます。

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
5
Kent Chenery

以下があなたに役立つかどうかはわかりませんが(多くの素晴らしい答えがあったため)、バックアップ履歴にアクセスできる場合は、次のようなクエリで以前のバックアップが圧縮されているかどうかを判断できると思います。

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
2
KookieMonster