【问题标题】:Improving performance of a while loop (C# code) calling a T-SQL stored procedure提高调用 T-SQL 存储过程的 while 循环(C# 代码)的性能
【发布时间】:2016-05-20 22:41:26
【问题描述】:

当存储过程 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
                }
            }
        }
    }
}

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

几个细节:

  • SelectNewObjects 返回从 Table1 创建的临时表中的记录。

  • if / else 块中,我正在更新 addObjectTable1 字段/strong> 完成。

  • addObject 方法通过使用 SOA(面向服务的体系结构)将 SQL 临时表中找到的每条记录插入到单独的 Oracle 系统中。我没有被授予访问底层数据库的权限,所以我不得不接受这种做事方式。

  • 有时临时表预计会有超过 20,000 条记录(每个只有两个字段:NameDescription),所以这很快就会变成一场噩梦。

在某一时刻,应用程序池将失败并出现以下两个错误(取自 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 返回的数万条记录,并更快地对每条记录执行操作?

【问题讨论】:

  • 如果确定是 C# 代码中的瓶颈?如果您要在 Management Studio 中执行相同的存储过程,时间安排是多少?
  • 把问题一分为二:注释掉while循环的内部,看看存储过程和数据检索时间是否可以接受。

标签: c# tsql iis-7 application-pool


【解决方案1】:

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

【讨论】:

  • 感谢您将数据存储在 List 对象中的提示 - 我这样做了,并且对于这个特定的 SP,我不再遇到这些问题。我将在代码的另一部分(另一个 while 循环调用对 SQL DB 的 INSERT 查询)复制此解决方案以改进它。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多