Não sendo um DBA e não tendo privilégios de administrador de sistema para fazer um backup/restauração, o seguinte seria uma boa solução para copiar um conjunto de tabelas? (Eu tenho um servidor vinculado de serverA
para serverB
)
copyTables
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[copyTables]
AS
-- NOCOUNT ON added to prevent extra result sets from interfering
-- with SELECT statements. XACT_ABORT ON to terminate the transaction
-- and rollback if a run-time error occurs.
SET NOCOUNT, XACT_ABORT ON
BEGIN
DECLARE @serverName varchar(50), @dbName varchar(50), @schemaName varchar(50)
SET @serverName = QUOTENAME('serverB')
SET @dbName = QUOTENAME('db')
SET @schemaName = QUOTENAME('dbo')
BEGIN TRY
BEGIN TRANSACTION
EXEC [dbo].[copyTable] @serverName, @dbName, @schemaName, 'tbl1', 'copyLog'
EXEC [dbo].[copyTable] @serverName, @dbName, @schemaName, 'tbl2', 'copyLog'
EXEC [dbo].[copyTable] @serverName, @dbName, @schemaName, 'tbl3', 'copyLog'
...
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- Insert error into log table
ROLLBACK
END CATCH
END
GO
copyTable
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[copyTable]
@serverName varchar(50),
@dbName varchar(50),
@schemaName varchar(50),
@tableName varchar(50),
@logTableName varchar(50)
AS
-- NOCOUNT ON added to prevent extra result sets from interfering
-- with SELECT statements. XACT_ABORT ON to terminate the transaction
-- and rollback if a run-time error occurs.
SET NOCOUNT, XACT_ABORT ON
BEGIN
DECLARE @localFullName varchar(200), @localShortName varchar(150),
@foreignFullName varchar(200), @logShortName varchar(150);
SET @localFullName = QUOTENAME(@dbName) + '.' + QUOTENAME(@schemaName)
+ '.' + QUOTENAME(@tableName);
SET @localShortName = QUOTENAME(@schemaName) + '.' + QUOTENAME(@tableName);
SET @foreignFullName = QUOTENAME(@serverName) + '.' + QUOTENAME(@dbName)
+ '.' + QUOTENAME(@schemaName) + '.' + QUOTENAME(@tableName);
SET @logShortName = QUOTENAME(@logTableName) + '.' + QUOTENAME(@schemaName)
+ '.' + QUOTENAME(@tableName);
IF EXISTS
(
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(@localShortName)
AND type in (N'U')
)
BEGIN
DROP TABLE @localShortName;
SELECT *
INTO @localFullName
FROM @foreignFullName;
INSERT INTO @logShortName (stamp, [message])
VALUES
(
GETDATE(),
'Table ' + @foreignFullName + ' was copied'
);
END
END
Isso parece uma boa solução de trabalho. Tenha em mente, no entanto, que copiar grandes quantidades de dados em uma transação aumentará potencialmente seus arquivos de log significativamente. Isso custa muito tempo e pode causar escassez inesperada de espaço na unidade. Além disso, durante esse período, as tabelas de destino ficam completamente inacessíveis para conexão externa. As guias de origem também podem ser bloqueadas, dependendo do nível de isolamento da transação.
Pode ser melhor dividir a movimentação de dados real em pequenos lotes. Mas então você perderia a consistência transacional se as gravações simultâneas acontecessem.
Como Aaron mencionou, você também pode querer olhar para ferramentas existentes como DataCompare (também não garantiria consistência transacional). Se você precisar executar esse processo de cópia regularmente, também poderá examinar a replicação de instantâneo. (Isso garantiria consistência transacional, mas precisaria ser configurado por um administrador de sistema. No entanto, após essa configuração inicial, você mesmo poderia iniciar a sincronização.)
Finalmente, se você for com sua solução, certifique-se de que, na condição de erro, você primeiro reverta a transação e, em seguida, registre na tabela de log de erros, caso contrário, você também reverterá essa nova entrada. Você também deve verificar se realmente existe uma transação no momento do erro:
IF XACT_STATE() != 0 ROLLBACK