提高调用 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 返回的数万条记录,并更快地对每条记录执行操作?

提高调用 T-SQL 存储过程的 while 循环(C# 代码)的性能

我假设这是因为通过线路插入 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
    }