Dapper dot net 中的 buffered 参数有啥作用?
Posted
技术标签:
【中文标题】Dapper dot net 中的 buffered 参数有啥作用?【英文标题】:What does the buffered parameter do in Dapper dot net?Dapper dot net 中的 buffered 参数有什么作用? 【发布时间】:2012-09-23 17:35:04 【问题描述】:Dapper dot net 有一个buffer
参数(一个布尔值),但据我所知,它所做的唯一 事情是将结果转换为列表,然后再返回。
根据documentation:
Dapper 的默认行为是执行你的 sql 并缓冲整个 读者返回。这在大多数情况下是理想的,因为它可以最大限度地减少共享 锁定数据库并减少数据库网络时间。
但是,在执行大型查询时,您可能需要最小化内存 足迹并仅根据需要加载对象。为此通过,缓冲: false 进入 Query 方法。
我不确定将结果转换为列表如何实现这一点。我错过了什么吗?我唯一的想法是它应该将ExecuteReader
的CommandBehavior
设置为CommandBehavior.SequentialAccess
(但它没有)。
【问题讨论】:
Explanation of dapper buffer/cache 的副本,@Marc 的回答稍长、详细(尽管不可否认,实际上是在这个问题之后提出的)。 @Groo,如果在这个问题之后问了另一个问题,那么 other 问题是重复的,而不是这个问题。 【参考方案1】:但据我所知,它唯一能做的就是在返回结果之前将结果转换为列表
你没有错过任何东西。这是关键的区别。除了它不是 cast 本身:实际返回的对象是非常不同的。读取数据基本上有两种方式:
在流式 API 中,每个元素都是单独生成的;这是非常节省内存的,但是如果您对每个项目进行大量后续处理,则意味着您的连接/命令可能会在较长时间内处于“活动状态” 在缓冲 API 中,所有行都被读取在产生任何东西之前如果您正在读取大量数据(数千到数百万行),则非缓冲 API 可能更可取。否则会使用大量内存,甚至在第一行可用之前可能会有明显的延迟。但是,在大多数常见场景中,读取的数据量都在合理的范围内,因此在将其交给调用者之前将其推送到列表中是合理的。这意味着命令/阅读器等已完成在返回之前。
附带说明一下,缓冲模式还避免了常见的“连接上已经有一个打开的阅读器”(或任何确切的措辞)。
【讨论】:
【参考方案2】:我不得不不同意@chris-marisic 的观点...我在使用 buffered:true 时在该行 (data.ToList()
) 遇到了多个“内存不足”异常。这不是一个“zillion rows X bazillion columns”查询,只是一个常规的 5-6k 行 SQL 结果,大约 30 列。
这真的取决于你的配置。例如。您的 SQL 和 IIS 是否在同一台物理机上运行。以及在 IIS 机器上安装了多少内存,以及页面文件设置是什么等。如果 Web 服务器有 2 GB 或更少 - 考虑为超重报告设置“buffered:false”。
【讨论】:
详细说明:data.ToList() 无论如何都会在内存中创建一个完整的列表。因此,如果您使用的是 buffered:true,您可能会在内存中获得两次列表。data.ToList()
我引用了 dapper 源代码中的实际行。【参考方案3】:
在实践中,最好永远不要使用 buffered: false
。
我发现甚至读取了数百万行,使用缓冲结果比无缓冲结果更快,内存效率更高。如果您的表有 500 列并且您正在读取数以百万计或数以亿计的行,则可能存在交叉点。
如果您的结果集小于数十亿个值,则无论出于何种原因都不值得使用buffered: false
。
在实际分析过程中,我感到震惊的是,在标准缓冲模式下,从 Sql Server 读取千兆字节数据的速度更快(快 2-6 倍)和内存效率更高。性能提升甚至考虑了可能的最微小操作,即通过索引将对象添加到稀疏数组到不调整大小的数组。使用多 GB 稀疏数组从无缓冲切换到有缓冲,加载时间提高了 2 倍。使用缓冲写入字典时,在插入数百万条记录时加载时间缩短了 6 倍(字典使用表的 int PK 作为键,以便尽可能地进行哈希码计算)。
与所有有关性能的事情一样,您必须始终进行分析。不过,我可以非常肯定地告诉您总是从 Dapper 的默认缓冲行为开始。
【讨论】:
克里斯,当您谈论填充数组或写入字典时,您是在谈论如何处理 Dapper 已经返回的结果?所以从技术上讲,这就是分析您自己的后缓冲读取代码?或者您是在谈论从较低级别的 SQL Server 处理结果?。 @Rich 使用foreach(item in unbuffered) dictionary.Add(item.Id, item)
比 bufferedquery.ToDictionary(x=> x.Id)
慢 6 倍。使用无缓冲存在明确的延迟成本。 (我正在阅读数百万和数亿的集合,注意我还为字典使用了适当大小的容量构造函数)
所以你确实在谈论我的想法。惊人的。非常有用的信息,谢谢。
@ChrisMarisic 我们正在使用 S3 的 Multipart Upload 支持。我们一次上传片段,S3 在完成后将它们组合起来。可以说无缓冲和缓冲的 Dapper 查询都有很好的用例。我们对大多数 API 调用使用缓冲,但我们也限制结果计数以避免资源问题。
@ChrisMarisic 啊,“我的路还是高速公路。”不用担心。围观者可以做出自己的判断。以上是关于Dapper dot net 中的 buffered 参数有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章