2012-09-17 22 views
4

假设我在本地有一个表,它是Local_Table,我有另一个服务器和另一个数据库和表,这是Remote_Table(表结构相同)。有数据,Remote_Table不。我想将数据从Local_Table这个查询传送到Remote_Table链接服务器插入选择性能

Insert into RemoteServer.RemoteDb..Remote_Table 
select * from Local_Table (nolock) 

但性能是相当缓慢。

但是,当我使用SQL Server导入导出向导时,传输速度非常快。

我在做什么错?为什么使用导入 - 导出向导快速并且插入选择语句慢?有任何想法吗?

回答

1

导入/导出向导将本质上作为批量插入操作,其中代码不是。

假设您在远程表上有一个群集索引,请确保您在本地表上具有相同的群集索引,在远程服务器上全局设置跟踪标志610,并确保远程处于简单或批量日志恢复模式。

如果你是远程表是堆(这无论如何都会加快速度),请确保您的远程数据库是简单或大容量日志记录模式改变你的代码如下:

INSERT INTO RemoteServer.RemoteDb..Remote_Table WITH(TABLOCK) 
SELECT * FROM Local_Table WITH (nolock) 
+0

这对性能没有任何影响。 –

+0

这个答案其实是非常真实的,但它不适合这个问题/主题 - 然而,任何人阅读它应该知道这是很好的建议,因此我upvote的答案,但这个评论。 –

0

的从本地表插入到远程表的速度太慢的原因是,它插入一行,检查它是否插入,然后插入下一行,检查它是否插入等。

不知道是否你弄明白了这一点,但这里是我如何使用链接服务器解决这个问题。

首先,我有几个列的LocalDB.dbo.Table:

IDColumn (int, PK, Auto Increment) 
TextColumn (varchar(30)) 
IntColumn (int) 

而且我有一个RemoteDB.dbo.Table几乎是一样的:

IDColumn (int) 
TextColumn (varchar(30)) 
IntColumn (int) 

的主要区别是远程IDColumn没有设置为一个ID列,所以我可以插入它。

然后,我设置了对发生在删除

Create Trigger Table_Del 
    On Table 
    After Delete 
AS 
Begin 
    Set NOCOUNT ON; 

    Insert Into Table (IDColumn, TextColumn, IntColumn) 
    Select IDColumn, TextColumn, IntColumn from MainServer.LocalDB.dbo.table L 
     Where not exists (Select * from Table R WHere L.IDColumn = R.IDColumn) 

END 

然后,当我想要做的插入,我不喜欢这样从本地服务器的远程表的触发器:

Insert Into LocalDB.dbo.Table (TextColumn, IntColumn) Values ('textvalue', 123); 
Delete From RemoteServer.RemoteDB.dbo.Table Where IDColumn = 0; 

--And if I want to clean the table out and make sure it has all the most up to date data: 
Delete From RemoteServer.RemoteDB.dbo.Table 

通过触发远程服务器从本地服务器获取数据,然后执行插入操作,我可以将需要30分钟的作业插入到需要8秒才能完成相同插入操作的作业中。

这确实需要双方的链接服务器连接,但在设置之后,它工作得很好。

更新:
因此,在过去的几年里,我做了一些修改,并已经从删除触发器离开,以此来同步远程表。

相反,我有一个具有所有从本地服务器获取数据的步骤在远程服务器上的存储过程:

CREATE PROCEDURE [dbo].[UpdateTable] 
    -- Add the parameters for the stored procedure here 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- Insert statements for procedure here 

    --Fill Temp table 
    Insert Into WebFileNamesTemp Select * From MAINSERVER.LocalDB.dbo.WebFileNames 

    --Fill normal table from temp table 
    Delete From WebFileNames 
    Insert Into WebFileNames Select * From WebFileNamesTemp 

    --empty temp table 
    Delete From WebFileNamesTemp 
END 

而且本地服务器我有一个计划作业,做了一些处理上当地表,然后通过触发存储过程的更新:

EXEC sp_serveroption @server='REMOTESERVER', @optname='rpc', @optvalue='true' 
EXEC sp_serveroption @server='REMOTESERVER', @optname='rpc out', @optvalue='true' 
EXEC REMOTESERVER.RemoteDB.dbo.UpdateTable 
EXEC sp_serveroption @server='REMOTESERVER', @optname='rpc', @optvalue='false' 
EXEC sp_serveroption @server='REMOTESERVER', @optname='rpc out', @optvalue='false' 
+0

这看起来像是一个非常具体的解决方案,对于您的用例来说并不是很好 - 如果在您将更大更好的项目移动到更大更好的项目后进行实际删除,那么突然发现我有更多的行比之前我删除,因为你运行同步?这是一个噩梦,找到为什么给予删除触发器.. –

+0

此解决方案主要是确保远程服务器匹配本地,并可以从本地服务器上的作业触发。这并不意味着是一个双向的事情。它基本上是说同样的事情,以至于在我之后回答的两个人都这样做。推慢,拉快。自从我想出如何使用远程存储过程以来,我已经从过去3年的删除触发器中移开。它避免了意外删除问题。如果远程服务器需要最新的信息,我会在运行时从本地拉出一两行,但大多数内容并没有改变。 – AndyD273

4

的最快方法是提取数据,而不是推。当按下表格时,每行都需要连接,插入和断开连接。

如果因为在服务器之间存在单向信任关系而无法获取数据,则解决方法是将整个表构建为巨大的T-SQL语句并一次运行。

DECLARE @xml XML 

SET @xml = (
     SELECT 'insert Remote_Table values (' + '''' + isnull(first_col, 'NULL') + ''',' + 
      -- repeat for each col 
      '''' + isnull(last_col, 'NULL') + '''' + ');' 
     FROM Local_Table 
     FOR XML path('') 
     ) --This concatenates all the rows into a single xml object, the empty path keeps it from having <colname> </colname> wrapped arround each value 

DECLARE @sql AS VARCHAR(max) 

SET @sql = 'set nocount on;' + cast(@xml AS VARCHAR(max)) + 'set nocount off;' --Converts XML back to a long string 

EXEC ('use RemoteDb;' + @sql) AT RemoteServer 
+1

每一行。哇。那么,这就解释了每秒插入速度<100行。 '从远程服务器中选择*到LocalTable中,100,000行只花了一两秒钟的时间。但是'从LocalTable插入到RemoteServer'在运行一分钟后只插入了1000行。疯。谁设计了这个可怕的系统? – Triynko

0

如果你必须推动从源数据到目标(例如,防火墙或其他权限的原因),你可以做到以下几点:

在源数据库,记录转换为单一XML字符串(即多行和多列组合成一个XML字符串)。 然后将该XML作为单个行(作为varchar(max),因为在SQL Server中的链接数据库上不允许使用XML)。

DECLARE @xml XML 

    SET @xml = (select * from SourceTable FOR XML path('row')) 

    Insert into TempTargetTable values (cast(@xml AS VARCHAR(max))) 

在目标数据库中,施放VARCHAR(最大值)为XML,然后使用XML解析把该单个的行和列返回到正常的记录集。

DECLARE @X XML = (select '<toplevel>' + ImportString + '</toplevel>' from TempTargetTable) 

DECLARE @iX INT 
EXEC sp_xml_preparedocument @ix output, @x 

insert into TargetTable 
SELECT [col1], 
     [col2] 
FROM OPENXML(@iX, '//row', 2) 
WITH ([col1] [int], 
     [col2] [varchar](128) 
) 

EXEC sp_xml_removedocument @iX 
相关问题