关于sql server:复制数据库的最佳方法是什么?

关于sql server:复制数据库的最佳方法是什么?

What is the best way to copy a database?

当我想复制一个数据库时,我总是创建一个新的空数据库,然后将现有数据库的备份恢复到其中。但是,我想知道这是否真的是最不容易出错、最不复杂和最有效的方法?


可以跳过创建空数据库的步骤。您可以在还原过程中创建新数据库。

这实际上是我所知道的克隆数据库的最简单和最好的方法。您可以通过编写备份和还原过程脚本来消除错误,而不是通过 SQL Server Management Studio

运行它

您可以探索其他两个选项:

  • 分离数据库,复制 .mdf 文件并重新附加。
  • 使用 SQL Server Integration Services (SSIS) 复制所有对象
  • 我建议在必要时坚持备份和恢复以及自动化。


    这是我过去使用过的动态 sql 脚本。它可以进一步修改,但它将为您提供基础知识。我更喜欢编写脚本以避免使用 Management Studio 时可能犯的错误:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    Declare @OldDB varchar(100)
    Declare @NewDB varchar(100)
    Declare @vchBackupPath varchar(255)
    Declare @query varchar(8000)


    /*Test code to implement
    Select @OldDB = 'Pubs'
    Select @NewDB = 'Pubs2'
    Select @vchBackupPath = '\\\\dbserver\\C$\\Program Files\\Microsoft SQL Server\\MSSQL.1\\MSSQL\\Backup\\pubs.bak'
    */

    SET NOCOUNT ON;

    Select @query = 'Create Database ' + @NewDB
    exec(@query)

    Select @query = '
    Declare @vBAKPath varchar(256)
    declare @oldMDFName varchar(100)
    declare @oldLDFName varchar(100)
    declare @newMDFPath varchar(100)
    declare @newLDFPath varchar(100)
    declare @restQuery varchar(800)

    select @vBAKPath = ''' + @vchBackupPath + '''
    select @oldLDFName = name from ' + @OldDB +'.dbo.sysfiles where filename like ''%.ldf%''
    select @oldMDFName = name from  ' + @OldDB +'.dbo.sysfiles where filename like ''%.mdf%''
    select @newMDFPath = physical_name from ' + @NewDB +'.sys.database_files where type_desc = ''ROWS''
    select @newLDFPath = physical_name from ' + @NewDB +'.sys.database_files where type_desc = ''LOG''

    select @restQuery = ''RESTORE DATABASE ' + @NewDB +
    ' FROM DISK = N'' + '''''''' + @vBAKpath + '''''''' +
    '' WITH MOVE N'' + '''''''' + @oldMDFName + '''''''' +  
    '' TO N'' + '''''''' + @newMDFPath + '''''''' +  
    '', MOVE N'' + '''''''' + @oldLDFName + '''''''' +  
    '' TO N'' + '''''''' + @newLDFPath + '''''''' +  
    '', NOUNLOAD, REPLACE, STATS = 10''

    exec(@restQuery)
    --print @restQuery'


    exec(@query)

    备份和恢复是我所知道的最直接的方法。您必须在服务器之间小心,因为恢复的数据库不附带安全凭证。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    ::================ BackUpAllMyDatabases.cmd ============= START
    ::BackUpAllMyDatabases.cmd
    :: COMMAND LINE BATCH SCRIPT FOR TAKING BACKUP OF ALL DATABASES

    ::RUN THE SQL SCRIPT VIA THE COMMAND LINE WITH LOGGING
    sqlcmd -S localhost -e  -i"BackUpAllMyDatabases.sql" -o Result_Of_BackUpAllMyDatabases.log

    ::VIEW THE RESULTS
    Result_Of_BackUpAllMyDatabases.log

    ::pause
    ::================ BackUpAllMyDatabases.cmd ============= END


    --=================================================BackUpAllMyDatabases.sql start
    DECLARE @DBName varchar(255)

    DECLARE @DATABASES_Fetch int

    DECLARE DATABASES_CURSOR CURSOR FOR
        select
            DATABASE_NAME   = db_name(s_mf.database_id)
        from
            sys.master_files s_mf
        where
           -- ONLINE
            s_mf.state = 0

           -- Only look at databases to which we have access
        and has_dbaccess(db_name(s_mf.database_id)) = 1

            -- Not master, tempdb or model
        --and db_name(s_mf.database_id) not in ('Master','tempdb','model')
        group by s_mf.database_id
        order by 1

    OPEN DATABASES_CURSOR

    FETCH NEXT FROM DATABASES_CURSOR INTO @DBName

    WHILE @@FETCH_STATUS = 0
    BEGIN
        declare @DBFileName varchar(256)    
        set @DBFileName = @DbName + '_' + replace(convert(varchar, getdate(), 112), '-', '.') + '.bak'
    --REMEMBER TO PUT HERE THE TRAILING \\ FOR THE DIRECTORY !!!
        exec ('BACKUP DATABASE [' + @DBName + '] TO  DISK = N''D:\\DATA\\BACKUPS\' +
            @DBFileName + ''' WITH NOFORMAT, INIT,  NAME = N''' +
            @DBName + '-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD,  STATS = 100')

        FETCH NEXT FROM DATABASES_CURSOR INTO @DBName
    END

    CLOSE DATABASES_CURSOR
    DEALLOCATE DATABASES_CURSOR

    --BackUpAllMyDatabases==========================end

    --======================RestoreDbFromFile.sql start
    -- Restore database from file
    -----------------------------------------------------------------
    use master
    go

    declare @backupFileName varchar(100), @restoreDirectory varchar(100),
    @databaseDataFilename varchar(100), @databaseLogFilename varchar(100),
    @databaseDataFile varchar(100), @databaseLogFile varchar(100),
    @databaseName varchar(100), @execSql nvarchar(1000)

    -- Set the name of the database to restore
    set @databaseName = 'ReplaceDataBaseNameHere'
    -- Set the path to the directory containing the database backup
    set @restoreDirectory = 'ReplaceRestoreDirectoryHere' -- such as 'c:\\temp\'

    -- Create the backup file name based on the restore directory, the database name and today's date

    @backupFileName = @restoreDirectory + @databaseName + '-' + replace(convert(varchar, getdate(), 110), '-', '.') + '.bak'


    -- set @backupFileName = 'D:\\DATA\\BACKUPS\\server.poc_test_fbu_20081016.bak'

    -- Get the data file and its path
    select @databaseDataFile = rtrim([Name]),
    @databaseDataFilename = rtrim([Filename])
    from master.dbo.sysaltfiles as files
    inner join
    master.dbo.sysfilegroups as groups
    on

    files.groupID = groups.groupID
    where DBID = (
    select dbid
    from master.dbo.sysdatabases
    where [Name] = @databaseName
    )

    -- Get the log file and its path
    select @databaseLogFile = rtrim([Name]),
    @databaseLogFilename = rtrim([Filename])
    from master.dbo.sysaltfiles as files
    where DBID = (
    select dbid
    from master.dbo.sysdatabases
    where [Name] = @databaseName
    )
    and
    groupID = 0

    print 'Killing active connections to the"' + @databaseName + '" database'

    -- Create the sql to kill the active database connections
    set @execSql = ''
    select @execSql = @execSql + 'kill ' + convert(char(10), spid) + ' '
    from master.dbo.sysprocesses
    where db_name(dbid) = @databaseName
    and
    DBID <> 0
    and
    spid <> @@spid
    exec (@execSql)

    print 'Restoring"' + @databaseName + '" database from"' + @backupFileName + '" with '
    print ' data file"' + @databaseDataFile + '" located at"' + @databaseDataFilename + '"'
    print ' log file"' + @databaseLogFile + '" located at"' + @databaseLogFilename + '"'

    set @execSql = '
    restore database [' + @databaseName + ']
    from disk = ''' + @backupFileName + '''
    with
    file = 1,
    move ''' + @databaseDataFile + ''' to ' + '''' + @databaseDataFilename + ''',
    move ''' + @databaseLogFile + ''' to ' + '''' + @databaseLogFilename + ''',
    norewind,
    nounload,
    replace'

    exec sp_executesql @execSql

    exec('use ' + @databaseName)
    go

    -- If needed, restore the database user associated with the database
    /*
    exec sp_revokedbaccess 'myDBUser'
    go

    exec sp_grantdbaccess 'myDBUser', 'myDBUser'
    go

    exec sp_addrolemember 'db_owner', 'myDBUser'
    go

    use master
    go
    */
    --======================RestoreDbFromFile.sql

    "发布到提供者"功能对我来说非常有用。请参阅 Scott Gu 的博客条目。

    如果您需要一些真正强大的东西,请查看此处的 redgate 软件工具...如果您正在执行大量 SQL,那么这些都是值得的。


    推荐阅读