提高调用 T-SQL 存储过程的 while 循环(C# 代码)的性能
本文关键字:循环 while 代码 性能 T-SQL 高调用 调用 存储过程 | 更新日期: 2023-09-27 18:34:06
当存储过程 SelectNewObjects 返回很少 (~500( 条记录时,以下 SqlCommand 工作正常,没有明显的性能问题。但是,当它返回超过 1,000 条记录时,我开始遇到性能问题:
using (SqlCommand cmdAddNewObject = new SqlCommand("SelectNewObjects", con))
{
cmdAddNewObject.CommandType = CommandType.StoredProcedure;
cmdAddNewObject.Parameters.AddWithValue("@parameter1", parameter1);
using (SqlDataReader rdrAddNewObject = cmdAddNewObject.ExecuteReader())
{
while (rdrAddNewObject.Read())
{
if (rdrAddNewObject.GetString(0) != null)
{
try
{
addObject(parameter1, rdrAddNewObject.GetString(0), rdrAddNewObject.GetString(0).Length / 4, rdrAddNewObject.GetString(0).Substring(0, 2),
rdrAddNewObject.GetString(0).Substring(2, 2), rdrAddNewObject.GetString(1));
if (rdrAddNewObject.GetString(1) == "No description found")
{
// Do something
}
else
{
// Do something else
}
}
catch (Exception ex)
{
// Throw exception
}
}
}
}
}
简单来说,我在这里所做的是为 SelectNewObject 返回的每条记录调用一个方法 (addObject(。
几个细节:
选择新对象 返回从 Table1 创建的临时表中的记录。
在 if/else 块中,我正在更新临时表中相关记录的 Table1 字段,在 addObject 的执行完成后。
addObject 方法通过使用 SOA(面向服务的体系结构(将 SQL 临时表中的每条记录插入到单独的 Oracle 系统中。我无法访问底层数据库,所以我不得不接受这种做事方式。
有时,临时表预计有超过 20,000 条记录(每个只有两个字段:名称和说明(,因此这很快就会成为一场噩梦。
在某一时刻,应用程序池将失败,并显示以下两个错误(取自 IIS 7 Windows 事件查看器(:
事件 ID 5013:为应用程序池".NET v4.5"提供服务的进程在关闭期间超出了时间限制。进程 ID 为"5616"。
事件 ID 5138:为应用程序池".NET v4.5"提供服务的工作进程"5616"无法停止协议"http"的侦听器通道分配的时间。 数据字段包含错误号。
technet.microsoft.com 和 support.microsoft.com 中对这些事件 ID 的描述并没有过多地说明此性能问题,并且对其根本原因没有定论。
也就是说,有没有办法改进 C# 代码以处理 SP 返回的数万条记录,并更快地对每条记录执行操作?
我假设这是因为通过线路插入 oracle 数据库需要很长时间,并且保持 SQL 连接打开的时间比它应该打开的时间长。因此,您需要将数据存储在临时集合中,然后循环访问列表或批量发送(如果执行后者,则需要将其分解,否则将达到限制(
例如
List<ObjectToStoreInOracle> items = new List<ObjectToStoreInOracle>();
using (SqlCommand cmdAddNewObject = new SqlCommand("SelectNewObjects", con))
{
cmdAddNewObject.CommandType = CommandType.StoredProcedure;
cmdAddNewObject.Parameters.AddWithValue("@parameter1", parameter1);
using (SqlDataReader rdrAddNewObject = cmdAddNewObject.ExecuteReader())
{
while (rdrAddNewObject.Read())
{
if (rdrAddNewObject.GetString(0) != null)
{
try
{
// add items to temp array list
items.Add(new ObjectToStoreInOracle(parameter1, rdrAddNewObject.GetString(0), rdrAddNewObject.GetString(0).Length / 4, rdrAddNewObject.GetString(0).Substring(0, 2), rdrAddNewObject.GetString(0).Substring(2, 2), rdrAddNewObject.GetString(1))))
if (rdrAddNewObject.GetString(1) == "No description found")
{
// Do something
}
else
{
// Do something else
}
}
catch (Exception ex)
{
// Throw exception
}
}
}
}
}
AddToOracleDB(items)
private void AddToOracleDB(List<ObjectToStoreInOracle> items){
//do stuff here to add to the Oracle DB
}