【问题标题】:SQL Stored Procedure Throws Error every 25 minutesSQL 存储过程每 25 分钟抛出一次错误
【发布时间】:2016-11-22 19:08:42
【问题描述】:

我有一个每 25 分钟抛出一个错误的存储过程。我在应用程序中有代码,当它失败时会向我发送电子邮件。我正在尝试确定是否是程序本身导致了问题,或者它是否可能与服务器上发生的其他事情发生冲突,或者应用程序中的代码是否可能出错。直到本周它都运作良好。本周我们对应用程序进行了更改,并向 ADT_Diagnosis 表添加了新代码。自从添加代码以来,它一直在抛出错误。感谢所有提示和建议。提前致谢!

这是它发送给我的错误:

护理床服务发生错误。 ”System.Data.SqlClient.SqlException (0x80131904): 超时。在操作完成之前超时时间已过或服务器没有响应。在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常,Boolean breakConnection) 在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException 异常,Boolean breakConnection) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() 在 System.Data .SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 在 System.Data.SqlClient.SqlDataReader.ConsumeMetaData() 在 System.Data.SqlClient.SqlDataReader.get_MetaData() 在 System.Data .SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) 在 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) 在 System.Data.SqlClient.SqlCommand.RunExecuteReader( CommandBehavior cmdBehavior、RunBehavior runBehavior、Boolean returnStream、String 方法、DbAsyncResult 结果)在System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior 行为,String 方法)的 System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior 行为,String 方法)的 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,布尔 returnStream,String 方法)( ) 在 Service.MainWindow.UpdateDataFromADT_Codes(SqlConnection SqlConn) 在 Service.MainWindow.TaskThread_DoWork(Object sender, DoWorkEventArgs e)

这里是 SQL 存储过程:

ALTER PROCEDURE GetActivePatientCoreMeasures 
   -- 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;

SELECT DISTINCT ADT.[PV1 Room],adt.[Patient Account Number], 
    [Diagnosis Codes].Description
FROM [CPSISQL].dbo.ADT
LEFT JOIN [CPSISQL].dbo.ADT_Diagnosis 
ON [CPSISQL].dbo.ADT.[Patient Account Number] =
    [CPSISQL].dbo.ADT_Diagnosis.[Patient Account #]
RIGHT JOIN [Diagnosis Codes]
ON ADT_Diagnosis.[Diagnosis Code] = [Diagnosis Codes].Code
WHERE [CPSISQL].dbo.ADT.[PV1 Discharge Date/Time] = ''
AND
(
[CPSISQL].dbo.ADT.[PV1 Department] = '028' OR
[CPSISQL].dbo.ADT.[PV1 Department] = '030' OR
[CPSISQL].dbo.ADT.[PV1 Department] = '032' OR
[CPSISQL].dbo.ADT.[PV1 Department] = '038' OR
[CPSISQL].dbo.ADT.[PV1 Department] = '042' 
)
AND NOT(ADT_Diagnosis.[Diagnosis Type] = 'A')
ORDER BY adt.[PV1 Room]
END

【问题讨论】:

  • 表定义(包括索引)、实际执行计划等......没有一些实际细节,这是一个废话。这可能是一个很好的起点。 spaghettidba.com/2015/04/24/… 从错误消息中可以清楚地看出您的 sql 连接超时。那可能是因为这个过程太慢了。可能是你等了很久。这可能是很多事情。

标签: sql sql-server vb.net stored-procedures


【解决方案1】:

您需要排除连接问题。见SQL Connection Error: System.Data.SqlClient.SqlException (0x80131904)。

如果这不能解决问题,请从 SSMS (SQL Server Management Studio) 手动运行存储过程,最好在错误发生后立即运行,并查看需要多长时间才能恢复。 VB.NET 中的默认命令超时时间为 30 秒,因此如果 SSMS 需要更长的时间,则意味着您必须增加超时时间(请参阅Set custom default CommandTimeout for all new Command Objects),或者使您的存储过程更快。

为了让您的存储过程更快,请从 SSMS 再次运行它,但这次确保启用“包括实际执行计划”。这将告诉您查询计划中的哪些操作需要更长的时间,甚至可以建议将哪些索引添加到您的表中以提高性能。

【讨论】:

  • 不是默认值._commandTimeout = 30;的常量值?
【解决方案2】:

首先,检查以确保您已从运行应用程序的机器连接到 SQL 服务器(不要忘记检查应用程序上使用的配置文件)。

它也可能是某种类型的网络块,例如防火墙或需要配置的不同连接类型(命名管道与 tcp/ip)。您可以通过 SQL Server 配置管理器检查 SQL Server 的配置。

【讨论】:

    【解决方案3】:

    如果不了解您的数据库和所涉及的表,就很难诊断您的问题。但是,存储过程中的查询写得很奇怪,可能是性能问题的原因。你不知道有多少次我重写了某人的丑陋查询,突然之间事情开始变得更好。所以我会解决这个问题。

    有些事情是没有意义的:

    • DISTINCT 的意义何在。我不知道你的数据库的结构,但如果你把它去掉,你可能会看到你返回了数百万行,因为你的连接有问题(你的连接肯定有问题)。
    • ADT_Diagnosis 有一个LEFT JOIN,但ADT_Diagnosis 也用于WHERE 子句中的必需谓词中。因此,如果 ADT_Diagnosis 中没有与 ADT 匹配的行,则该谓词自动为假,并且根本不会返回任何行。您可能会想 != 'A" 允许 NULL 值,但 NULL 既不是 = 'A' 也不是 != 'A' 所以它自动为假。
    • *诊断代码有一个RIGHT JOIN。 ADT_Diagnosis 中似乎不太可能有人希望返回没有匹配行的描述。这可能会导致一个大错误。这都是学术性的,因为上一点中提到的谓词将阻止任何行返回。不过,它可能会让查询规划器感到困惑。
    • NOT(ADT_Diagnosis.[Diagnosis Type] = 'A') 写成 ADT_Diagnosis.[Diagnosis Type] != 'A' 不太容易混淆。
    • 不要重复OR 多次,而是使用IN。
    • 奖励:随意使用较短的别名代替表名。这将使查询更易于阅读。

    考虑到上述几点,这是重写的查询。因为涉及ADT_Diagnosis 的谓词要求从该表返回一行,所以我将连接从LEFT 和RIGHT 更改为INNER,因为该表分别位于右侧和左侧。这解决了第二点和第三点。多次出现的“或”已被删除并替换为IN。

    我没有删除DISTINCT,因为我对这些表了解不够。我见过很多例子,其中DISTINCT 用于修复连接错误的查询结果,因此可能不再需要。

    SELECT DISTINCT adt.[PV1 Room],adt.[Patient Account Number], codes.Description
    FROM [CPSISQL].dbo.ADT adt
    INNER JOIN [CPSISQL].dbo.ADT_Diagnosis diag
      ON adt.[Patient Account Number] = diag.[Patient Account #]
    INNER JOIN [Diagnosis Codes] codes ON diag.[Diagnosis Code] = codes.Code
    WHERE adt.[PV1 Discharge Date/Time] = ''
      AND adt.[PV1 Department] IN ('028','030','032', '038', '042')
      AND diag.[Diagnosis Type] != 'A'
    ORDER BY adt.[PV1 Room]
    

    这应该返回完全相同的结果,但希望(并且可能)有一个更好的计划。

    【讨论】:

    • “似乎不太可能有人希望在 ADT_Diagnosis 中没有匹配行的情况下返回描述”。有了这个假设,您正在更改查询的输出,它不会“返回完全相同的结果”。假设外部连接是有原因的会更安全。您正在更改查询,但没有回答原始问题或对问题没有任何了解。
    • @Diego 我没有更改输出。如果您阅读了声明的其余部分,我会说重点是学术性的,因为WHERE 子句中的AND NOT(ADT_Diagnosis.[Diagnosis Type] = 'A') 将阻止出现在ADT_Diagnosis 中不匹配的任何描述。
    • 感谢您的信息!我们输入了新的存储过程代码,不幸的是,我们仍然如预期的那样按时收到错误。我们将继续寻找答案,并感谢任何帮助或反馈。丹尼尔,我对存储过程一团糟并不感到惊讶。这是我们第一次学习时写的。这是其中之一“嘿!它有效!”时刻,我们从未简化它。 Diego,我们确信这不是连接问题。如果是这样,我们将每 15-30 秒收到一次错误,但感谢您的建议。
    猜你喜欢
    • 2015-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 2012-11-06
    相关资源
    最近更新 更多