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、次のように 1 つのステートメントのみを含めようとしました。

   select @a=1

しかし、それは非常に奇妙です.全体の手順の速度はまったく変わらないように見えます.それでも多くの時間を費やしています.誰か理由を教えてもらえますか? ありがとう。

4

3 に答える 3

2

これは、更新または削除が最適化されていないためであると考えたので、プロシージャを変更してsp_app_RatePlanDetail_Add_0909、次のように 1 つのステートメントのみを含めようとしました。

select @a=1

しかし、それは非常に奇妙です。手順全体の速度はまったく変わらないように見えますが、まだ多くの時間を費やしています。誰か理由を教えてもらえますか? ありがとう。

鉱山を強調します。

これは、問題がレイテンシに関連していることを示しています (または、ストアド プロシージャのパフォーマンスがパフォーマンスの問題の原因ではないことを示しています。他の場所を探すことを検討してください)。つまり、ストアド プロシージャを実行するための要求を送信して結果を受け取るまでの時間は、ストアド プロシージャの実行にかかる時間よりもはるかに長くなります。

ストアド プロシージャはレコードごとに 1 回呼び出すため、待機時間によって "無駄になる" 時間は 8,000 倍になります。

テーブル値パラメーターを使用して多くのレコードを一度にストアド プロシージャにストリーミングすることで、往復の回数を大幅に減らすことができます。

テーブル値パラメーターの使用は万能薬ではないことに注意してください。ストアド プロシージャは、パラメーター スニッフィングが原因でパフォーマンスが低下する可能性があります。

于 2013-09-09T07:59:46.483 に答える
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 に答える
0

実行に時間がかかりすぎているのはストアド プロシージャだと思いますか? それとも、DataGridView を介したループ全体の実行について言及していますか? 私が知る限り、実際にはデータベースへの 8000 の接続を開いたり閉じたりしているため、それ自体に時間がかかる可能性があります。

于 2013-09-09T07:54:38.133 に答える