“yield”在遍历数据读取器对象时对连接状态和代码性能的影响是什么?

16

这是我用来从数据库获取数据的示例代码: 在DAO层:

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层,我调用上述方法的方式如下:

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

在映射器层,MapMultiple方法定义如下:

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

上述代码运行良好,但我对以上代码有两个顾虑。

  1. 数据读取器的连接将保持多长时间开放状态?
  2. 仅考虑代码性能因素时,使用 'yield return' 而不是将记录添加到列表并返回整个列表是否是一个好主意?
3个回答

18
  1. 你的代码没有展示打开/关闭连接的地方;但是在这里 读取器 只会在 迭代数据时保持打开状态。延迟执行等。你的代码中唯一完成这个操作的部分是 .ToList(),所以没问题。在更普遍的情况下,是的:读取器将在迭代它所需时间内保持打开状态;如果你做一个 .ToList() 那么将是最小限度的;如果你用一个 foreach 并且(对于每个项目)进行外部http请求并等待20秒,则是的 - 它将打开更长时间。
  2. 两者都有各自的用途;非缓冲区方法非常适合处理巨大的结果,您希望将其作为流处理,而无需将它们加载到单个内存列表中(甚至不必同时拥有所有结果);返回列表可以快速关闭连接,并使避免意外使用已经具有打开阅读器的连接变得容易,但不适用于大型结果。

如果返回一个迭代器块,调用者可以决定什么是合理的;如果总是返回一个列表,他们选择余地不多。第三种方式(我们在Dapper中使用)是让选择成为调用者的责任;我们有一个可选的 bool 参数,默认为“返回列表”,但调用者可以更改以表示“返回迭代器块”;基本上:

bool buffered = true

在参数中,以及:

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

在实现中,大多数情况下返回列表是完全合理的并且避免了很多问题,因此我们将其设为默认值。


4

数据读取器的连接会保持多久?

连接将保持打开状态,直到 reader 被关闭,这意味着它将一直保持打开状态,直到迭代结束。

仅考虑代码性能因素时,使用 yield return 而不是将记录添加到列表并返回整个列表是一个好主意吗?

这取决于几个因素:

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

0

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

这是一个权衡 - 无法在不知道系统约束条件的情况下判断是否是一个好主意 - 您期望获取多少数据,您愿意接受多少内存消耗,数据库的预期负载等等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接