Проблема производительности DataReader, странное поведение - PullRequest
0 голосов
/ 08 июня 2018

У меня такая же проблема, как у Большие проблемы с производительностью с Oracle DataReader в .Net .Моя хранимая процедура использует объединение всех по двум запросам (каждый из них использует несколько объединений).Всего SP возвращает около 20 тысяч записей за 10 секунд.Что выглядит нормально.

Но я сталкиваюсь с проблемами на стороне приложения, когда dataReader.Read () занимает около четырех минут, чтобы просто получить эти данные.Ниже приведен код, который я сейчас использую:

        List<int> ordinalIndexes = new List<int>();

        foreach (string headerName in headerColumnMapping.Keys)
            ordinalIndexes.Add(dataReader.GetOrdinal(headerColumnMapping[headerName].ToString()));

        while (dataReader.Read())
        {
            foreach (var ordinalIndex in ordinalIndexes)
                csvString.AppendFormat("\"{0}\"{1}", dataReader[ordinalIndex].ToString().Trim(), separator);
        }

Я заметил, что в dataReader.Read () есть много фрагментов, которые легко обрабатываются (менее миллисекунд).Но есть много других, которые занимают 10-35 секунд (для одного чтения).

Я пытался:

  1. Оптимизация SP.Не уверен, что этот SP можно оптимизировать больше?
  2. Пробовал реализовать MARS (как предложено в Действительно странная проблема производительности DataReader ).Но у меня это не сработало.

Любые предложения по этому поводу очень ценятся.

Ответы [ 2 ]

0 голосов
/ 15 июня 2018

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

Спасибо за @Steve за ваш вклад в изменения уровня приложения.Хотя, для моего случая, производительность БД была настоящим виновником.

0 голосов
/ 08 июня 2018

Невозможно выполнить тестирование с вашими данными, но некоторые оптимизации могут быть добавлены в ваш цикл.
Например, не форматируйте каждое отдельное поле, а форматируйте целую строку.

Вы можете попытаться адаптировать этот код кваши данные

string separator = ";";
int pos = 0;
string format = "";

// Prepare the format mask for the whole records
foreach (string headerName in headerColumnMapping)
{
    format += "\"{" + pos  + "}\"" + separator;
    pos++;
}
// Remove the last separator and add a newline
format = format.Substring(0, format.Length - 1) + "\r\n";

// Create the array of the field positions
var range = Enumerable.Range(0, reader.FieldCount);

// Set an initial capacity for the string builder to 10MB
// Of course this could be a waste of memory if you plan to retrieve
// small amounts of data.
StringBuilder csvString = new StringBuilder(1024*1024*10);

while (dataReader.Read())
{
    var x = dataReader as IDataRecord;

    // Create the array of the field values
    var k = range.Select(r => x[r].ToString()).ToArray();

    // Append the whole line
    csvString.AppendFormat(format, k);  
}

Приведенный выше код извлекает все поля из хранилища данных.Если вы хотите получить только некоторые поля, отображенные в вашем списке ordinalIndexes , просто удалите создание диапазона и используйте свой текущий код, чтобы подготовить список целых чисел для извлечения.Затем замените range.Select на ordinalIndexes.Select

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

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

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