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

Improving performance of a while loop (C# code) calling a T-SQL stored procedure

当存储过程 SelectNewObjects returns 很少(~500)条记录时,以下 SqlCommand 工作正常,没有明显的性能问题。但是,当它 returns 超过 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
                }
            }
        }
    }
}

简而言之,我在这里所做的是为 SelectNewObjects 返回的每条记录调用一个方法 (addObject)。

几个细节:

在某一时刻,应用程序池将失败并出现以下两个错误(取自 IIS 7 Windows 事件查看器):

technet.microsoft.com 和 support.microsoft.com 中对这些事件 ID 的描述并没有过多地说明此性能问题,也没有确定其根本原因。

也就是说,有没有什么方法可以改进 C# 代码以处理 SP 返回的数万条记录,并更快地对每条记录执行操作?

我假设这是因为通过线路插入 oracle DB 需要很长时间,并且 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
    }