运行多服务器SQL Server查询时出现超时错误

时间:2017-05-01 17:30:22

标签: c# sql-server

我在本地SQL Server中将链接服务器定义为远程服务器。

我在连接本地和远程服务器时运行查询,如下所示:

SELECT *
FROM [RemteServer].[RemoteDB].[dbo].[Links]
WHERE Id NOT IN
    (
    SELECT ExternalId
    FROM [dbo].[Links]
    )

当我在SQL Server Management Studio上运行此查询时,它会在2分钟内执行,但是当我在连接到本地SQL Server的本地计算机上的C#程序上运行它时会产生超时错误。

我将C#连接字符串上的connect timeout设置为600.我还将链接服务器属性上的Connection timeoutQuery timeout设置为600。

如何防止超时错误?

P.S:SQL服务器版本是2008.我使用Visual Studio 2015并在VS上使用ADO连接。

3 个答案:

答案 0 :(得分:1)

我的建议是将大量此查询迁移到SQL Server上,并使用存储过程来完成工作。

SQL Server

CREATE PROCEDURE dbo.lsp_GetRemoteLinks
AS
BEGIN
    IF OBJECT_ID('tempdb..#RemoteLinks') IS NOT NULL DROP TABLE #RemoteLinks

    SELECT    *
    INTO      #RemoteLinks
    FROM        [RemteServer].[RemoteDB].[dbo].[Links]

    SELECT    *
    FROM        #RemoteLinks
    WHERE    (Id NOT IN (SELECT ExternalId FROM [dbo].[Links] ))

    DROP TABLE #RemoteLinks
END
GO

<强> C#

    DataTable RemoteLinks = new DataTable();
    using (SqlConnection conn = new SqlConnection(strConn)) {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand("lsp_GetRemoteLinks", conn)) {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandTimeout = 120;
            RemoteLinks.Load(cmd.ExecuteReader());
        }
        conn.Close();
    }

这会减少您的时间,但我确实增加了CommandTimeout值。

如果这个数据不需要“生动”它的新鲜度我会考虑制作一个永久的本地表并使用 SQL Agent 定期重新填充它,然后你会能够在表格上使用索引来进一步提高效率。

答案 1 :(得分:0)

您在此查询上的表现并不理想,因为您实际上是在尝试将链接服务器中的每条记录读取到正在执行查询的本地服务器上。如果您可以通过添加将在远程服务器上执行的WHERE子句来过滤结果,那么您的性能将显着提高。

DECLARE @ExtLinks TABLE (Id INT)
INSERT INTO @ExtLinks (Id)
SELECT ID 
FROM [RemteServer].[RemoteDB].[dbo].[Links]
--WHERE Princess = 'Zelda'

SELECT * FROM @ExtLinks
WHERE Id NOT IN
    (
    SELECT ExternalId
    FROM [dbo].[Links]
    ) 

答案 2 :(得分:-1)

我敢打赌,你的查询中最大的问题是你在IN子句中有一个SELECT。这通常是一个非常糟糕和不必要的实践,因为服务器通常会选择再次运行该select语句,对外部查询中的每个记录执行一次,以便它可以测试其ID是否确实不在内部集合中。将您的查询更改为:

WITH CTE_ExternalIDs (ID)
   AS (SELECT ExternalId FROM [dbo].[Links])
SELECT * from [RemteServer].[RemoteDB].[dbo].[Links]
 LEFT OUTER JOIN JOIN CTE_ExternalIDs ON [RemteServer].[RemoteDB].[dbo].[Links].ID = CTE_ExternalIDs.ID
 WHERE CTE_ExternalIDs.ID is null

或者最好转一下查询并在RemoteDB上进行CTE。