关于c#:我想知道迭代数据读取器对象时’yield’的连接状态和对代码性能的影响

I am wondering about the state of connection and impact on code performance by 'yield' while iterating over data reader object

下面是我用来从数据库中获取数据的示例代码:论刀层:

1
2
3
4
5
6
7
8
9
10
11
public IEnumerable<IDataRecord> GetDATA(ICommonSearchCriteriaDto commonSearchCriteriaDto)
{
    using(DbContext)
    {
        DbDataReader reader = DbContext.GetReader("ABC_PACKAGE.GET_DATA", oracleParams.ToArray(), CommandType.StoredProcedure);
        while (reader.Read())
        {
            yield return reader;
        }
    }
}

在bo层,我调用上面的方法,比如:

1
List<IGridDataDto> GridDataDtos = MapMultiple(_costDriversGraphDao.GetGraphData(commonSearchCriteriaDto)).ToList();

在映射器层上,mapmultiple方法的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public IGridDataDto MapSingle(IDataRecord dataRecord)
{
    return new GridDataDto
    {
        Code = Convert.ToString(dataRecord["Code"]),
        Name = Convert.ToString(dataRecord["Name"]),
        Type = Convert.ToString(dataRecord["Type"])    
    };
}
public IEnumerable<IGridDataDto> MapMultiple(IEnumerable<IDataRecord> dataRecords)
{
    return dataRecords.Select(MapSingle);
}

上面的代码运行良好,但是我想知道上面代码的两个问题。

  • 数据读取器的连接将打开多长时间?
  • 当我只考虑代码性能因素时,使用"yield return"而不是将记录添加到列表中并返回整个列表是一个好主意吗?

  • 您的代码没有显示您在哪里打开/关闭连接;但是这里的读卡器实际上只在您迭代数据时打开。延迟执行等。您的代码中唯一可以执行这一操作的是.ToList(),这样就可以了。在更一般的情况下,是的:读卡器将打开一段时间来迭代它;如果您执行.ToList(),这将是最小的;如果您执行foreach,并且(对于每个项目)发出一个外部HTTP请求并等待20秒,那么是的-它将打开更长的时间。
  • 两者都有各自的用途;非缓冲方法非常适用于希望作为流处理的巨大结果,而无需将它们加载到单个内存中列表中(甚至一次将所有这些列表都存储在内存中);返回列表可使连接快速关闭,并使连接在运行时很容易避免意外使用连接。eady有一个开放的阅读器,但不适合大的结果
  • 如果您返回一个迭代器块,调用方可以决定什么是正常的;如果您总是返回一个列表,那么它们没有太多的选项。第三种方法(我们在dapper中做的)是选择它们的;我们有一个可选的bool参数,默认为"返回一个列表",但调用方可以更改该参数来表示"返回一个迭代器块";基本上:

    1
    bool buffered = true

    在参数中,和:

    1
    2
    var data = QueryInternal<T>(...blah...);
    return buffered ? data.ToList() : data;

    在实施中。在大多数情况下,返回一个列表是完全合理的,可以避免很多问题,因此我们将其设置为默认值。


    How long data reader’s connection will be opened?

    连接将保持打开,直到取消reader,这意味着它将一直打开,直到迭代结束。

    When I consider code performance factor only, Is this a good idea to use yield return instead of adding record into a list and returning the whole list?

    这取决于几个因素:

    • 如果您不打算获取整个结果,yield return将帮助您节省在网络上传输的数据量。
    • 如果您不打算将返回的数据转换为对象,或者如果多行用于创建单个对象,yield return将帮助您节省在程序的峰值使用点使用的内存。
    • 如果您计划在短时间内迭代Enture结果集,那么使用yield return不会受到性能惩罚。如果迭代将在多个并发线程上持续相当长的时间,那么RDBMS端打开的游标数可能会超过。


    这个答案忽略了所示实现中的缺陷,并涵盖了一般的思想。

    这是一种权衡——不知道系统的约束条件就无法判断这是否是一个好主意——您期望获得的数据量、您愿意接受的内存消耗、数据库的预期负载等等。