DataReader性能问题,奇怪的行为

时间:2018-06-08 20:08:31

标签: c# asp.net oracle

我面临与Big Performance Problems With Oracle DataReader in .Net类似的问题。我的存储过程在两个查询上使用union all(每个查询都使用一些连接)。总之,SP在10秒内返回大约20K的记录。看起来没问题。

但是,我面临着应用程序方面的问题,其中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(如Really odd DataReader performance issue中所述)。但它对我不起作用。
  3. 对此有任何建议都很高兴。

2 个答案:

答案 0 :(得分:1)

无法测试您的数据,但可以在循环中添加一些优化 例如,不要格式化每个单独的字段,而是格式化整行。

您可以尝试将此代码调整为您的数据

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);  
}

上面的代码从datareader中检索所有字段。如果只想检索通过 ordinalIndexes 列表映射的某些字段,则只需删除范围的创建,然后使用当前代码准备要检索的整数列表。然后将 range.Select 替换为 ordinalIndexes.Select

另一个小东西,但有大量的支出是定义StringBuilder的容量,特别是如果你希望检索大量的数据。如果立即定义足够大的初始容量,则可以避免在缓冲区填满时重新分配内存。

但是,如果您尝试导出CSV文件,我建议您查看一些专门创建CSV文件的库。如果你有更好的表现,你可能会检查它们。

答案 1 :(得分:0)

通过优化存储过程解决了我的问题。我添加了一些索引(基于SP中的查询),整体性能在很大程度上得到了改善。

感谢@Steve提供有关应用程序级别更改的输入。虽然,就我而言,数据库性能是真正的罪魁祸首。