c # Optimized Выберите цикл создания строки - PullRequest
1 голос
/ 03 декабря 2009

Я ищу, чтобы оптимизировать этот кусок кода. Он обработает 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");

Ответы [ 9 ]

4 голосов
/ 03 декабря 2009

Вы обязательно должны взглянуть на StringBuilder - это чудесно работает для подобных сценариев. В этом случае я бы использовал сочетание AppendFormat и Append . Мне нравится 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");
2 голосов
/ 03 декабря 2009

Используйте StringBuilder и его Append () метод.

1 голос
/ 03 декабря 2009

Я парень из базы данных, так что, надеюсь, я здесь не идиот, но вы можете использовать класс StringBuilder? Я не знаю, требует ли это .NET Framework или нет.

1 голос
/ 03 декабря 2009

После беглого взгляда выделяется то, что вы должны использовать класс StringBuilder для создания строки, вместо того, чтобы постоянно конкатенироваться к строковой переменной strSelect. Выдержка из связанной статьи MSDN:

Выполнение операции конкатенации для строки или Объект StringBuilder зависит от того, как часто происходит выделение памяти. Операция конкатенации строк всегда выделяет память, тогда как Операция конкатенации StringBuilder только выделяет память, если Буфер объекта StringBuilder слишком маленький для размещения новых данных. Следовательно, класс String предпочтительнее для объединения операция, если фиксированное число строк объекты объединены. В этом случай, индивидуальная конкатенация операции могут быть даже объединены в одна операция компилятора. Объект StringBuilder предпочтительнее для операция конкатенации, если произвольное количество строк сцеплены; например, если цикл объединяет случайное число строки ввода пользователя.

1 голос
/ 03 декабря 2009

Чтобы ответить на ваш прямой вопрос, вы почти наверняка выиграете от использования StringBuilder для построения строки, а затем ToString () в конце.

Однако, если бы вы могли дать нам обзор намерения (чтобы нам не приходилось разбираться с ним, чтобы вывести его), мы, вероятно, могли бы порекомендовать лучший способ.

1 голос
/ 03 декабря 2009

Вы пробовали объект StringBuilder? http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx

1 голос
/ 03 декабря 2009

Используйте StringBuilder для манипулирования строками, например strSelect + = ... вместо этого используйте stringBuilder.Append ("...");

1 голос
/ 03 декабря 2009

Используйте StringBuilder вместо конкатенации строк.

0 голосов
/ 04 декабря 2009

Вы получили много хороших предложений по использованию StringBuilder. Чтобы еще больше повысить производительность и, поскольку вы ожидаете большого результата строки, я бы также порекомендовал вам выбрать хорошую начальную емкость, чтобы уменьшить количество раз, когда внутренний буфер строки необходимо расширять.

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

Обратите внимание, что я выбрал 8192 символа здесь, но вы можете инициализировать его большим числом, если вы действительно добавляете "9000" строк данных к вашему состоянию. Определите свой типичный размер и установите его на небольшую величину.

Способ работы StringBuilder заключается в том, что, когда вы добавляете строку и достигаете текущей емкости, он должен создать новый буфер и скопировать содержимое старого буфера в новый, а затем добавить новые символы. Чтобы оптимизировать производительность, новый буфер будет в два раза больше старого размера. Теперь начальная емкость по умолчанию составляет либо 16 символов, либо размер строки инициализации. Если длина получаемой строки составляет 5000 символов, то StringBuilder, созданный с размером по умолчанию, должен быть расширен в 9 раз - для этого требуется новое выделение памяти и копирование всех предыдущих символов! Однако, если вы знали, что это будет происходить регулярно, и создали StringBuilder с нужной емкостью, дополнительного выделения или копий не было бы.

Обычно вам не нужно беспокоиться о внутренних операциях объекта, но иногда вы делаете это для производительности, подобной этой. Поскольку StringBuilder предоставляет вам способ указать рекомендуемую начальную емкость, воспользуйтесь этим. Вы не знаете, изменится ли алгоритм двойного копирования / копирования в будущем, а также может измениться первоначальная емкость по умолчанию, но ваша спецификация начальной емкости будет продолжать выделять правильного размера застройщика - потому что это является частью публичного контракта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...