0

我有一个包含大约 8000 条记录的 datagridview,对于每条记录,我调用 SQL Server 存储过程将其插入数据库,代码如下:

for (int i = 0; i < dgv_compare.Rows.Count; i++)
{
    if (!DBCommands.sp_app_RatePlanDetail_Add(
                CarrierID,
                is_supplier == 1 ? 0 : 1,
                row.Prefix,
                row.RegionName,
                row.NewRate,
                row.FreeBlock,
                row.InitialBlock,
                row.RecycleBlock,
                row.ConnectionCharge,
                row.EnrollDate,
                row.ExpiryDate,
                row.isDisabled,
                row.TimeF1,
                row.TimeT1,
                row.Rate1,
                row.Block1Enabled,
                row.TimeF2,
                row.TimeT2,
                row.Rate2,
                row.Block2Enabled,
                row.TimeF3,
                row.TimeT3,
                row.Rate3,
                row.Block3Enabled,
                Operator,
                FlagShortOverLong,
                ref ErrCode,
                ref ErrMsg))
            {
                //tb_log.Text += DBCommands.LastError + "\r\n";
                MessageBox.Show(DBCommands.LastError);
                return;
            }
}

函数DBCommands.sp_app_RatePlanDetail_Add是这样的形式:

public static bool sp_app_RatePlanDetail_Add
(
    int CustID,
    int IsInBound,
    string Prefix,
    string RegionName,
    double RatePerMin,
    int FreeBlock,
    int InitialBlock,
    int RecycleBlock,
    double ConnectionCharge,
    DateTime EnrollDate,
    DateTime ExpiryDate,
    int isDisabled,
    TimeSpan TimeF1,
    TimeSpan TimeT1,
    double Rate1,
    int Block1Enabled,
    TimeSpan TimeF2,
    TimeSpan TimeT2,
    double Rate2,
    int Block2Enabled,
    TimeSpan TimeF3,
    TimeSpan TimeT3,
    double Rate3,
    int Block3Enabled,
    string Operator,
    int FlagShortOverLong,
    ref int ErrCode,
    ref string ErrMsg
)
{
    SqlConnection conn = null;
    SqlCommand sqlCmd = null;

    try
    {
        try
        {
            conn = new SqlConnection(ConnectString);
            conn.Open();

            if (conn.State != ConnectionState.Open)
            {
                LastErrorCode = -1;
                LastError = "Connect database error.";
                return false;
            }
        }
        catch (Exception ex)
        {
            LastErrorCode = -1;
            LastError = "Connect database error. " + ex.ToString();
            return false;
        }

        try
        {
            sqlCmd = new SqlCommand("sp_app_RatePlanDetail_Add_0909", conn);
            sqlCmd.CommandTimeout = ExecuteTimeout;
            sqlCmd.CommandType = CommandType.StoredProcedure;

            AddParam(sqlCmd, "@CustID", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, CustID);
            AddParam(sqlCmd, "@IsInBound", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, IsInBound);
            AddParam(sqlCmd, "@Prefix", SqlDbType.VarChar, 60, 30, 0, ParameterDirection.Input, Prefix);
            AddParam(sqlCmd, "@RegionName", SqlDbType.VarChar, 400, 200, 0, ParameterDirection.Input, RegionName);
            AddParam(sqlCmd, "@RatePerMin", SqlDbType.Decimal, 13, 20, 10, ParameterDirection.Input, RatePerMin);
            AddParam(sqlCmd, "@FreeBlock", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, FreeBlock);
            AddParam(sqlCmd, "@InitialBlock", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, InitialBlock);
            AddParam(sqlCmd, "@RecycleBlock", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, RecycleBlock);
            AddParam(sqlCmd, "@ConnectionCharge", SqlDbType.Decimal, 9, 18, 8, ParameterDirection.Input, ConnectionCharge);
            AddParam(sqlCmd, "@EnrollDate", SqlDbType.DateTime, 8, 23, 3, ParameterDirection.Input, EnrollDate);
            AddParam(sqlCmd, "@ExpiryDate", SqlDbType.DateTime, 8, 23, 3, ParameterDirection.Input, ExpiryDate);
            AddParam(sqlCmd, "@isDisabled", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, isDisabled);
            AddParam(sqlCmd, "@TimeF1", SqlDbType.Time, 5, 16, 7, ParameterDirection.Input, TimeF1);
            AddParam(sqlCmd, "@TimeT1", SqlDbType.Time, 5, 16, 7, ParameterDirection.Input, TimeT1);
            AddParam(sqlCmd, "@Rate1", SqlDbType.Decimal, 13, 20, 10, ParameterDirection.Input, Rate1);
            AddParam(sqlCmd, "@Block1Enabled", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, Block1Enabled);
            AddParam(sqlCmd, "@TimeF2", SqlDbType.Time, 5, 16, 7, ParameterDirection.Input, TimeF2);
            AddParam(sqlCmd, "@TimeT2", SqlDbType.Time, 5, 16, 7, ParameterDirection.Input, TimeT2);
            AddParam(sqlCmd, "@Rate2", SqlDbType.Decimal, 13, 20, 10, ParameterDirection.Input, Rate2);
            AddParam(sqlCmd, "@Block2Enabled", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, Block2Enabled);
            AddParam(sqlCmd, "@TimeF3", SqlDbType.Time, 5, 16, 7, ParameterDirection.Input, TimeF3);
            AddParam(sqlCmd, "@TimeT3", SqlDbType.Time, 5, 16, 7, ParameterDirection.Input, TimeT3);
            AddParam(sqlCmd, "@Rate3", SqlDbType.Decimal, 13, 20, 10, ParameterDirection.Input, Rate3);
            AddParam(sqlCmd, "@Block3Enabled", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, Block3Enabled);
            AddParam(sqlCmd, "@Operator", SqlDbType.VarChar, 60, 30, 0, ParameterDirection.Input, Operator);
            AddParam(sqlCmd, "@FlagShortOverLong", SqlDbType.Int, 4, 10, 0, ParameterDirection.Input, FlagShortOverLong);
            AddParam(sqlCmd, "@ErrCode", SqlDbType.Int, 4, 10, 0, ParameterDirection.Output, null);
            AddParam(sqlCmd, "@ErrMsg", SqlDbType.VarChar, 100, 50, 0, ParameterDirection.Output, null);


            sqlCmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int, 4);
            sqlCmd.Parameters["@RETURN_VALUE"].Direction = ParameterDirection.ReturnValue;
            sqlCmd.ExecuteNonQuery();

            ErrCode = get_int_value(sqlCmd.Parameters["@ErrCode"].Value);
            ErrMsg = get_string_value(sqlCmd.Parameters["@ErrMsg"].Value);

            int _temp = Convert.ToInt32(sqlCmd.Parameters["@RETURN_VALUE"].Value.ToString());
            return true;
        }
        catch (Exception ex)
        {
            LastErrorCode = -1;
            LastError = "Execute sp_app_RatePlanDetail_Add error. " + ex.ToString();
            return false;
        }
    }
    finally
    {
        if (sqlCmd != null)
            sqlCmd.Dispose();
        if (conn != null)
        {
            conn.Close();
            conn.Dispose();
        }
    }
}

因为我需要做一些检查和比较,所以我不能将 datagridview 保存到 csv 并一次插入整个数据集。

在这个程序sp_app_RatePlanDetail_Add_0909中,我做了一些更新和删除、插入操作,虽然可以工作,但是花费的时间太长了

我认为这可能是因为未优化更新或删除,所以我尝试更改过程sp_app_RatePlanDetail_Add_0909,让它只包含一个语句,如下所示:

   select @a=1

但是很奇怪,整个过程的速度好像一点变化都没有,还是要花很多时间,谁能告诉我是什么原因?谢谢。

4

3 回答 3

2

我认为这可能是因为未优化更新或删除,所以我尝试更改程序sp_app_RatePlanDetail_Add_0909,让它只包含一个语句,如下所示:

select @a=1

但是很奇怪,整个过程的速度似乎一点变化都没有,还是要花很多时间,谁能告诉我是什么原因?谢谢。

强调我的。

这表明您的问题与延迟有关(或者,存储过程的性能不是性能问题所在;考虑寻找其他地方)。也就是说,发送请求执行存储过程并接收结果的时间远大于执行存储过程的时间。

因为每条记录调用一次存储过程,由于延迟而“浪费”的时间增加了 8,000 倍。

您可以通过使用表值参数一次将许多记录流式传输到存储过程来显着减少往返次数。

请注意,使用表值参数不是万能药,您的存储过程可能会因参数嗅探而导致性能不佳。

于 2013-09-09T07:59:46.483 回答
0

您确定是存储过程执行时间过长吗?还是您指的是通过 DataGridView 执行整个循环?因为据我所知,您实际上是在打开和关闭与数据库的 8000 个连接,这本身可能会消耗一些时间。

于 2013-09-09T07:54:38.133 回答
0

似乎您为存储过程的每次调用打开/关闭了一个连接。如果你想提高性能,首先尝试使用单个连接而不是多个连接(即将连接作为参数传递给方法并在外部处理连接)。就像是:

using (SqlConnection con = new SqlConnection("your connection string")){
  con.Open();

  for (int i = 0; i < dgv_compare.Rows.Count; i++)
  {
     if (!DBCommands.sp_app_RatePlanDetail_Add(
                con,
                CarrierID,
                ...
  };

  con.Close();
}

相信这将缓解性能问题

于 2013-09-09T07:55:22.627 回答