如何判断 SQL Server 备份是否已压缩?

Han*_*non 6 sql-server backup sql-server-2012

我们最近从 SQL Server 2005 升级到 SQL Server 2012。在 SQL Server 2005 下,没有像 2012 年那样创建压缩备份的选项。

如果您尝试BACKUP DATABASE ... WITH (COMPRESSION);对已初始化但未压缩的文件进行操作,该BACKUP DATABASE命令将失败并显示以下错误消息:

ERROR MESSAGE : BACKUP DATABASE is terminating abnormally.
ERROR CODE : 3013
Run Code Online (Sandbox Code Playgroud)

如何判断现有备份文件是否针对压缩备份进行了初始化?

Aar*_*and 7

也许不是一遍又一遍地备份到同一个文件,您应该考虑WITH INIT始终使用一个新文件。我认为管理多个备份文件更简单,所有备份文件都在文件名中嵌入了自己的时间戳,并且能够单独存档/清除每个文件。当您不断将备份转储到同一个文件时,它只会变得越来越大,恕我直言更难以管理。没关系,你不再需要关心那个

此外,我不确定您为什么要打开和关闭备份压缩。你有没有发现禁用它更好的情况?您是否有实际用例,在支持压缩的版本上,您在不压缩的情况下进行一次性备份并使用相同的文件?为什么?

无论如何,你总是可以做一些非常简单的事情,比如:

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
Run Code Online (Sandbox Code Playgroud)

在任何工作完成之前,错误就会立即冒泡。

但我仍然认为一开始就不要一遍又一遍地使用同一个文件要好得多。恕我直言。


Han*_*non 6

我创建了以下存储过程,可用于确定数据库备份文件是否已初始化以进行压缩:

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
Run Code Online (Sandbox Code Playgroud)

该存储过程演示如何确定文件是否以各种方式,包括使用存在xp_cmdshell一个TRY...CATCH的情况下,块xp_cmdshell未启用,我的首选方法,xp_fileexists

我对这个存储过程的工作方式不太满意 - 我更喜欢更轻量级的版本。


JNK*_*JNK 6

这是一个方便的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


}
Run Code Online (Sandbox Code Playgroud)

将您的服务器名称和路径传递给 .BAK 文件,它将返回 1 或 0 以进行压缩。

请记住,.BAK 文件路径需要与您运行脚本的位置相关!

如果这将投入生产,您应该为文件不存在等内容添加一些错误捕获。


小智 6

要查看特定的数据库备份文件是否使用压缩进行备份,您可以对文件的标头信息进行错误处理:

RESTORE HEADERONLY FROM DISK = 'Path to backup file';
Run Code Online (Sandbox Code Playgroud)

返回的列之一被标记为“压缩”。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
Run Code Online (Sandbox Code Playgroud)