非常慢的 ExecuteNonQuery(存储过程)与使用 SQL Server Management Studio 的快速执行

Posted

技术标签:

【中文标题】非常慢的 ExecuteNonQuery(存储过程)与使用 SQL Server Management Studio 的快速执行【英文标题】:Very slow ExecuteNonQuery (Stored Procedure) vs fast execution using SQL Server Management Studio 【发布时间】:2015-08-31 12:21:09 【问题描述】:

尽管围绕这个主题有很多问题,但似乎没有一个建议有效。 我有几个应该每天运行的存储过程——其中一些存储过程非常简单,而另一些则比较棘手。但是,当使用 SqlClient 从 C# 程序(控制台)调用时,即使是最简单的过程也会无限期地运行。 此客户端正在服务器上运行,应在实际运行时升级为 Windows 服务。

到目前为止我已经尝试过。

    将 ARITHABORT ON(或 OFF)添加为连接初始化后的首次执行。 将 ARITHABORT ON(或 OFF)添加为存储过程中的第一个命令 使用WITH RECOMPILE 将 ARITHABORT 添加为全局配置事物。

(EXEC sys.sp_configure N'user options', N'64' GO RECONFIGURE WITH OVERRIDE GO)

存储过程(全部)有没有个输入参数,最简单的(我目前唯一使用的)是这样的:

CREATE PROCEDURE [dbo].[_clean_messageLog]
WITH RECOMPILE
AS
BEGIN
    SET NOCOUNT ON;
    set arithabort on;

    DELETE FROM MessageLog WHERE Moment < GETDATE() - 60;

    DELETE FROM MessageLog WHERE Moment < GETDATE() - 30 AND [Status] = 200;
END

实际上没有要删除的消息,并且在 SSMS 中,存储过程会在几毫秒内执行(如预期的那样)。 然而,从 C# 控制台应用程序需要永远(字面意思)。

主方法:

const int TIME_OUT = 900000; // 15 minutes
            timer.Stop();
            foreach (var command in commands.Where(command => !string.IsNullOrWhiteSpace(command)))
            
                var start = DateTime.Now;
                WriteEvent(string.Format("Starting: 0", command), EventLogEntryType.Information);
                using (var sql = new Lib.Data.SqlServerHelper(connectionString))
                
                    sql.newCommand(command.Trim());
                    sql.execute(TIME_OUT); 
                
                WriteEvent(string.Format("Done in 0 seconds", DateTime.Now.Subtract(start).TotalSeconds), EventLogEntryType.Information);
            

有人有建议吗?

编辑

sqlHelper 只是一个基本的(非常简单的)包装器。但即使我把上面的代码改成这样:

foreach (var command in commands.Where(command => !string.IsNullOrWhiteSpace(command)))
            
                var start = DateTime.Now;
                WriteEvent(string.Format("Starting: 0", command), EventLogEntryType.Information);
                using (var sql = new SqlConnection(connectionString))
                
                    sql.Open();
                    var sqlCommand = new SqlCommand(command.Trim(), sql) CommandType = CommandType.StoredProcedure;
                    sqlCommand.ExecuteNonQuery();
                
                WriteEvent(string.Format("Done in 0 seconds", DateTime.Now.Subtract(start).TotalSeconds), EventLogEntryType.Information);
            

完全一样。

编辑#2

是否有一个选项我可以安排这些存储过程由 SQL Server 本身按时间间隔或特定时间运行?

已解决

有点,虽然我从来没有找到使用 SQL Server 代理解决我的问题的实际 C# 解决方案。由于死锁问题,C# 进程被锁定 - 有时也会发生在作业上(不像控制台程序那么多),但我们正在努力解决这个问题。

【问题讨论】:

从应用程序运行 proc 时运行分析器跟踪,看看 proc 是否真的需要很长时间,而不是网络或您的应用程序。 您确定当您从应用程序调用时您的查询没有被其他人阻止吗? 删除“WITH RECOMPILE”并重建索引。 msdn.microsoft.com/en-us/library/ms191439(v=sql.105).aspx 可能会在这里为您提供帮助。 - 听起来你在给我重新发明作业调度程序。 在使用 c# 应用程序时,您是否在与 SP 调用相同的事务中插入 ocr 更新 MessageLog 表? 【参考方案1】:

是否有一个选项我可以安排这些存储过程由其运行

SQL Server 本身是否在某个时间间隔或特定时间?

是的,SQL Server 代理可以根据特定时间或间隔运行作业。

Creating SQL Server Job

SSMS -> SQL Server 代理 -> 右键单击​​ -> 新建作业 -> 选择名称、数据库、代码和计划

完成后,您可以单击Script 按钮并获取创建作业的脚本(如果需要)。

您也可以使用 T-SQL 启动 Job(例如从应用程序/另一个存储过程或触发器):

EXEC msdb.dbo.sp_start_job N'JobName';

【讨论】:

@Leon 寻找死锁我建议sp_whoisactive

以上是关于非常慢的 ExecuteNonQuery(存储过程)与使用 SQL Server Management Studio 的快速执行的主要内容,如果未能解决你的问题,请参考以下文章

.net中ExecuteNonQuery方法,返回操作行数,用存储过程时,为啥总是返回-1呢

转解决存储过程执行快,但C#程序调用执行慢的问题

c#: ExecuteNonQuery() 返回 -1

在SQL Server数据库中执行存储过程很快,在c#中调用很慢的问题

SQL Server 如何执行 带参数的 存储过程

如何优化太慢的存储过程? [关闭]