【发布时间】:2013-02-04 22:27:14
【问题描述】:
我有一个正在执行 INSERT 语句的存储过程,我们在执行时看到了明显的延迟。从我们的 C# .NET 应用程序运行它以连续插入 30 条记录时,总共需要大约 4 秒才能完成(仅计算运行 SqlCommand.ExecuteNonQuery() 方法所需的时间)。但是,从 SQL Server Management Studio 中以相同的次数调用完全相同的存储过程只需要大约 0.4 秒。我不知道这 2 种设置之间有什么不同会产生如此大的 10 倍速度差异。
我已经尝试了以下所有方法,但速度没有明显变化:
- 创建存储过程“WITH RECOMPILE”
- 检查在 SSMS 和 C# 中配置的所有“SET”值。唯一的区别是 SET ARITHABORT,它在 SSMS 中为 ON,而在从 .NET 应用程序调用时为 OFF。不过,在存储过程的开头添加“SET ARITHABORT ON”并没有什么不同。
- 从 sproc 参数中删除了所有默认值
用于从 .NET 应用程序调用存储过程的代码是:
using (SqlConnection newConn = new SqlConnection(connectionString))
{
using (SqlCommand uCmd = new SqlCommand("sproc_name", newConn))
{
uCmd.CommandType = CommandType.StoredProcedure;
uCmd.Connection.Open();
//About 15 parameters added using:
uCmd.Parameters.AddWithValue("@ParamName", value);
...
//One output parameter
SqlParameter paramOUT = new SqlParameter("@OutPutKey", SqlDbType.UniqueIdentifier);
paramOUT.Direction = ParameterDirection.Output;
uCmd.Parameters.Add(paramOUT);
uCmd.ExecuteNonQuery();
uCmd.Connection.Close();
}
}
存储过程本身只是一个设置命令列表(SET ANSI_NULLS ON、SET QUOTED_IDENTIFIER ON、SET ARITHABORT ON)、一个非默认参数列表,以及将成为新唯一标识符的输出变量的设置将作为主键插入到表中,然后是 INSERT 语句本身。
应用程序基于 .NET 4 构建,SQL 服务器为 MS SQL Server 2005。
这是它调用的插入存储过程的示例:
alter procedure InsertStuff
@Field1 uniqueidentifier,
@Field2 datetime,
...
@CreateDate datetime,
@PrimaryKEY uniqueidentifier OUTPUT
AS
declare @newCreateDate datetime
set @newCreateDate=getDate()
set @PrimaryKEY = NEWID()
INSERT INTO [dbo].[Table]
(
Field1,
Field2,
...
CreateDate,
PrimaryKEY
)
VALUES
(
@Field1,
@Field2,
...
@newCreateDate,
@PrimaryKEY
)
【问题讨论】:
-
没有看到存储过程很难回答,听起来你正在调用这个方法 30 次,但是从你的代码中你正在打开和关闭,将连接处理 30 次为出色地。保持连接打开,然后调用存储过程 30 次。
-
也只设置一次命令,每次调用只需添加参数值
-
这个问题可能对stackoverflow.com/questions/801909有帮助
-
如果您可以访问 sql server 所在的机器,我会在该机器和您的机器上设置一些性能计数器(或任何数据访问代码所在的位置 - 如果是这样的话,就像 Web 服务器一样) )。如果您跟踪 Bytes Received 和 Bytes Sent,您应该能够弄清楚网络占用了多少时间,以及它真正从数据库中出来的速度有多快。
-
如果此问题与 ARITH_ABORT 等环境问题有关,尝试在存储过程内部解决它们将无济于事;在调用 proc 之前,您需要在连接上设置 ARITHABORT ON - 并避免将您想要执行此操作的往返次数加倍,然后在同一连接上调用 proc 30 次而不“关闭”它(即使您正在使用连接池并且它并没有真正关闭)。