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

Posted

技术标签:

【中文标题】运行多服务器 SQL Server 查询时出现超时错误【英文标题】:Timeout error in running a multi-server SQL Server query 【发布时间】:2017-05-01 17:30:21 【问题描述】:

我在本地 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 server 版本是 2008。我使用 Visual Studio 2015,在 VS 上使用 ADO 连接。

【问题讨论】:

您应该使用msdn.microsoft.com/en-us/library/… CommandTimeout 而不是连接超时。将使用命令超时,因为您的查询需要很长时间才能运行。 CommandTimeoutSqlCommand相关,但我使用SqlDataAdapter获取执行查询的结果。 你仍然可以在 SqlDataAdapter 上使用 CommandTimeout 实例化它然后使用 yourvariable.SelectCommand.CommandTimeout = 0; 远程数据多久更改一次,还是连续的? @Mad,它在不断变化。 【参考方案1】:

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

SQL 服务器

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 代理 定期重新填充它,然后你会能够在桌子上使用索引来进一步提高效率。

【讨论】:

在 IN 子句和 WHERE 子句中包含 SELECT 通常对性能非常不利,而且是不必要的。尽管此类子查询有时确实有其用途,但这看起来并不需要。 我尽量减少对他的 SQL 语句的实际更改,有很多方法可以提高 SQL 性能,例如“丢失记录”连接。不存在的地方,删除等。对某些人有用的东西可能对其他人来说无法访问。 我测试了您提高性能的建议。由于我需要将所有字段传输到本地服务器(不仅是 ids),因此您的解决方案比我的解决方案慢 2.5 倍(我写了有问题的查询。)【参考方案2】:

您在此查询上的表现并不理想,因为您实际上是在尝试将链接服务器中的每条记录读取到正在执行查询的本地服务器上。如果您可以通过添加将在远程服务器上执行的 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]
    ) 

【讨论】:

我的问题是:如何增加执行查询超时。而不是如何提高我们的表现。 此外,您的解决方案甚至没有提高性能。因为我们需要将所有字段都转移到本地,而不仅仅是 Id。 增加查询超时只会掩盖眼前的问题。随着链接服务器表的增长,查询性能会下降,需要您不断增加查询超时,从而对最终用户体验产生负面影响。 从长远来看,过滤链接服务器上的数据会使您的工作更轻松。如果需要,您还可以添加更多字段。表变量示例只是为了说明这一点。 我测试它。但我认为在这两种情况下(我的查询和你的查询)都需要将本地表的 id 传输到远程,并将远程选定行的所有数据传输到本地。所以这些解决方案的时间可能没有区别。

以上是关于运行多服务器 SQL Server 查询时出现超时错误的主要内容,如果未能解决你的问题,请参考以下文章

Asp.Net 在运行存储过程时出现超时错误

使用 wcf 对 sql server 运行查询时出现奇怪的错误

Perl在使用警报超时时出现分段错误

在用Microsoft SQL Server 查询分析器时出现以下错误,请问是啥原因?

为啥我的SQL SERVER2005在连接ODBC时会出现连接超时过期呢

处理 ClientInsertServerInsert 同步冲突时出现 SQL 命令“超时”异常