【问题标题】:c# Optimized Select string creation loopc# 优化选择字符串创建循环
【发布时间】:2010-12-22 20:27:42
【问题描述】:

我希望优化这段代码。它将处理 15000 - 20000 行。现在我有 9000 行,大约需要 30 秒。我知道字符串连接很慢,但我不知道如何以另一种方式进行。

                    //
                    // Check if composite primary keys existe in database
                    //

                    string strSelect = "SELECT * FROM " + _strTableName + " WHERE ";
                    for (int i = 0; i < strCompositeKeyField.Length; i++)
                    {
                        bool boolKeyProcess = false;
                        strSelect += _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]] + " = ";
                        DataColumn thisColomn = _dsProcessDataFromFileAndPutInDataSetDataSet.Tables["Repartition"].Columns[_strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]]];
                        //_strProcessDataFromFileAndPutInDataSetLog += "Debug: Composite key : " + _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]] + " dataType : " + thisColomn.DataType.ToString() + " arrayListCompositeKeyIndex[i] = " + arrayListCompositeKeyIndex[i] + " \n";
                        // check if field is datetime to make convertion
                        if (thisColomn.DataType.ToString() == "System.DateTime")
                        {
                            DateTime thisDateTime = DateTime.ParseExact(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]], _strDateConvertion, null);
                            strSelect += "'" + thisDateTime.ToString() + "'";
                            boolKeyProcess = true;
                        }
                        // check if field a string to add ''
                        else if (thisColomn.DataType.ToString() == "System.String")
                        {
                            strSelect += "'" + strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]] + "'";
                            boolKeyProcess = true;
                        }
                        // check if field need hour to second converstion
                        else
                        {
                            for (int j = 0; j < strHourToSecondConverstionField.Length; j++)
                            {
                                if (strCompositeKeyField[i] == strHourToSecondConverstionField[j])
                                {
                                    DateTime thisDateTime = DateTime.ParseExact(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]], _strHourConvertion, System.Globalization.CultureInfo.CurrentCulture);

                                    strSelect += thisDateTime.TimeOfDay.TotalSeconds.ToString();
                                    boolKeyProcess = true;
                                }
                            }
                        }
                        // if not allready process process as normal
                        if (!boolKeyProcess)
                        {
                            strSelect += strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]];
                        }
                        // Add " AND " if not last field
                        if (i != strCompositeKeyField.Length - 1)
                        {
                            strSelect += " AND ";
                        }

                    }


                    //_strProcessDataFromFileAndPutInDataSetLog += "Debug: SELECT = " + strSelect + "\n";

                    SqlDataAdapter AdapterCheckCompositePrimaryKeys = new SqlDataAdapter(strSelect, _scProcessDataFrinFileAndPutInDataSetSqlConnection);
                    DataSet DataSetCheckCompositePrimaryKeys = new DataSet();

                    AdapterCheckCompositePrimaryKeys.Fill(DataSetCheckCompositePrimaryKeys, "PrimaryKey");

【问题讨论】:

    标签: c# sql string optimization concatenation


    【解决方案1】:

    您收到了很多使用 StringBuilder 的好建议。为了进一步提高性能,并且由于您期望得到较大的字符串结果,我还建议您选择一个好的初始容量以减少需要扩展内部字符串缓冲区的次数。

    StringBuilder strSelect = new StringBuilder("SELECT * FROM " + _strTableName + " WHERE ", 8192);
    

    请注意,我在这里选择了 8192 个字符,但如果您确实要在您的条件中添加“9000”行数据,您可能希望将其初始化为更大的数字。找出您的典型尺寸并将其容量设置为略高于该尺寸。

    StringBuilder 的工作方式是,当您追加到字符串并达到当前容量时,它必须创建一个新缓冲区并将旧缓冲区的内容复制到新缓冲区,然后追加新字符。为了优化性能,新缓冲区将是旧缓冲区的两倍。现在,默认初始容量是 16 个字符或初始化字符串的大小。如果生成的字符串长度为 5000 个字符,则使用默认大小创建的 StringBuilder 必须扩展 9 倍 - 这需要新的内存分配并复制所有以前的字符!但是,如果您知道这种情况会定期发生并创建具有正确容量的 StringBuilder,则不会有额外的分配或副本。

    通常您不需要担心对象的内部操作,但有时您会担心这样的性能。由于 StringBuilder 确实为您提供了一种指定推荐初始容量的方法,因此请利用它。您不知道双倍/复制算法将来是否会改变,初始默认容量也可能会改变,但您对初始容量的规范将继续分配正确大小的构建器 - 因为这是公共合同的一部分。

    【讨论】:

      【解决方案2】:

      您绝对应该看看StringBuilder - 它对于像这样的场景非常有效。在这种情况下,我会混合使用AppendFormatAppend。我倾向于喜欢AppendFormat 以使字符串更易于理解。

      //
      // Check if composite primary keys existe in database
      //
      
      StringBuilder strSelect = "SELECT * FROM " + _strTableName + " WHERE ";
      
      for (int i = 0; i < strCompositeKeyField.Length; i++)
      {
          bool boolKeyProcess = false;
      
          strSelect.AppendFormat("{0} =", 
              _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]]);
      
          DataColumn thisColomn = 
              _dsProcessDataFromFileAndPutInDataSetDataSet
              .Tables["Repartition"]
              .Columns[_strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]]];
      
          //_strProcessDataFromFileAndPutInDataSetLog += "Debug: Composite key : " + _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]] + " dataType : " + thisColomn.DataType.ToString() + " arrayListCompositeKeyIndex[i] = " + arrayListCompositeKeyIndex[i] + " \n";
          // check if field is datetime to make convertion
          if (thisColomn.DataType.ToString() == "System.DateTime")
          {
              DateTime thisDateTime = 
                  DateTime.ParseExact(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]], 
                 _strDateConvertion, null);
      
              strSelect.AppendFormat("'{0}'", thisDateTime.ToString());
              boolKeyProcess = true;
          }
          // check if field a string to add ''
          else if (thisColomn.DataType.ToString() == "System.String")
          {
              strSelect.AppendFormat("'{0}'", 
                  strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]]);
      
              boolKeyProcess = true;
          }
          // check if field need hour to second converstion
          else
          {
              for (int j = 0; j < strHourToSecondConverstionField.Length; j++)
              {
                  if (strCompositeKeyField[i] == strHourToSecondConverstionField[j])
                  {
                      DateTime thisDateTime = DateTime.ParseExact(
                          strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]],
                          _strHourConvertion, 
                          System.Globalization.CultureInfo.CurrentCulture);
      
                      strSelect.Append(thisDateTime.TimeOfDay.TotalSeconds.ToString());
                      boolKeyProcess = true;
                  }
              }
          }
          // if not allready process process as normal
          if (!boolKeyProcess)
          {
              strSelect.Append(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]]);
          }
          // Add " AND " if not last field
          if (i != strCompositeKeyField.Length - 1)
          {
              strSelect.Append(" AND ");
          }
      
      }
      
      
      //_strProcessDataFromFileAndPutInDataSetLog += "Debug: SELECT = " + strSelect + "\n";
      
      SqlDataAdapter AdapterCheckCompositePrimaryKeys = new SqlDataAdapter(strSelect.ToString(), _scProcessDataFrinFileAndPutInDataSetSqlConnection);
      DataSet DataSetCheckCompositePrimaryKeys = new DataSet();
      
      AdapterCheckCompositePrimaryKeys.Fill(DataSetCheckCompositePrimaryKeys, "PrimaryKey");
      

      【讨论】:

        【解决方案3】:

        我是一个数据库专家,所以希望我在这里听起来不像个白痴,但是你能使用 StringBuilder 类吗?我不知道这是否需要 .NET 框架。

        【讨论】:

          【解决方案4】:

          快速浏览后,突出的一件事是您应该使用StringBuilder 类来构建字符串,而不是不断地连接到您的 strSelect 字符串变量。摘自链接的 MSDN 文章:

          字符串或字符串的连接操作的性能 StringBuilder 对象取决于如何 经常发生内存分配。一种 字符串连接操作总是 分配内存,而 StringBuilder 连接操作 仅在 StringBuilder 对象缓冲区太 小以容纳新数据。 因此,String 类是 更适合串联 如果是固定数量的String,则操作 对象被连接起来。在那里面 情况下,单独的串联 操作甚至可以合并为 编译器的单个操作。一种 StringBuilder 对象更适合于 一个连接操作,如果 任意数量的字符串是 串联;例如,如果一个循环 连接一个随机数 用户输入的字符串。

          【讨论】:

            【解决方案5】:

            要回答您的直接问题,您几乎肯定会受益于使用 StringBuilder 构建字符串,然后在最后使用 ToString()。

            但是,如果您能给我们一个意图的概述(这样我们就不必费力地推断它),我们可能会推荐一个更好的方法。

            【讨论】:

              【解决方案6】:

              【讨论】:

                【解决方案7】:

                使用 StringBuilder 进行字符串操作,例如 strSelect += ... 而是使用 stringBuilder.Append("...");

                【讨论】:

                  【解决方案8】:

                  使用StringBuilder 而不是字符串连接。

                  【讨论】:

                    【解决方案9】:

                    使用StringBuilder 及其Append() 方法。

                    【讨论】:

                      猜你喜欢
                      • 2016-08-27
                      • 1970-01-01
                      • 2020-11-30
                      • 1970-01-01
                      • 2015-07-07
                      • 2011-07-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多