Ale*_*xei 7 sql-server sql-server-mars entity-framework-core asp.net-core
我编写的大多数应用程序都不使用MultipleActiveResultSets=True
,但我已经在其中几个和一些教程中看到启用了该选项。
这个SO 问题涉及相同的主题,但它已经很老了,我相信在此期间情况发生了很大变化。
OP 争论执行一些非查询,同时执行ExecuteReader
. 在这种情况下,我认为这是一个糟糕的设计,因为它可能会被一些批处理样式的操作取代,也许是一个存储过程,以最大限度地减少往返次数。
当将 Entity Framework 与 ASP.NET Core 一起使用并收到与已在范围内执行某些内容的数据上下文相关的异常时,我将其视为错误,并没有考虑启用 MARS。
读了这MS文档文章我看到一个要注意的各个方面,如选项(ANSI_NULLS
,DATE_FORMAT
,LANGUAGE
,TEXTSIZE
),安全性上下文,当前的数据库,状态变量(@@ERROR
,@@ROWCOUNT
,@@FETCH_STATUS
,@@IDENTITY
)与MARS工作时启用。
此外,如果确实需要,10 年以上意味着功能更强大的服务器能够保持更多连接(缓存应该有助于减少这种需求)。
所以我想知道在使用现代 ASP.NET Core 应用程序 (3.0+) 时是否必须考虑启用 MARS。
问题:在使用 ASP.NET Core 3.0 和 SQL Server 2019+ 时,我什么时候应该使用 MultipleActiveResultSets=True?
我对详尽的分析不感兴趣,但有几个合适的上下文来证明是否使用 MARS 是合理的。
ASP.NET Core 应用程序中的一个典型示例是将数据库上下文作为范围(每个请求从连接池获取一个数据库连接,进行更改,通常每个请求/范围一个事务)。到目前为止,我已经将与每个连接的多个查询相关的错误视为我自己的错误,以避免 MARS,但我这样做了,但我没有真正理解原因。
Iva*_*oev 10
是的,MARS 在现代数据访问框架中仍然占有一席之地,因为它们为以下两个主要的一般查询问题提供了(有效的)解决方案 - 流(即非缓冲)(1)具有预先加载的相关数据集合的数据和(2)懒惰加载任何类型的相关数据。
在这两种情况下,执行查询都应该提供IEnumerator<T>
(或其异步版本),它是数据读取器(或数据库前向只读游标)的对象等价物。因此,每个都MoveNext{Async}
应该映射到ReadNext
数据读取器,并期望提供一个完全填充的T
,没有缓冲在所有其他之前。为了实现这一点,底层数据读取器必须在枚举期间保持打开状态,并在完成或较早中止时关闭(例如,FirstOrDefault()
) - 原因之一IEnumerator<T>
是IDisposable
.
现在想象一下如果您启用了延迟加载会发生什么。您获得一些实体并访问一些导航属性。这就触发了延迟加载操作,当然需要执行reader从数据库中获取数据。由于外部阅读器仍处于打开状态(活动),因此在没有 MARS 的情况下,此操作只会因运行时异常而失败。不好。除了提前缓冲所有内容(基本上切换到快照模式)或不使用延迟加载之外,您或框架无能为力。
假设您不使用延迟加载(无论如何都不推荐)。但是您的实体包含相关的数据集合,并且您希望预先加载它们。关系数据库 SQL 提供平面结果集,即不支持查询结果集内部的“嵌套集合”。那么如何流式传输这些数据呢?
基本上有两种解决方案。
首先是基于包含所有主 + 相关表列的单个 SQL 查询,并返回某种混合记录,其中某些字段适用于特定结果而其他字段为空值。EF6 和 EF Core 3.0+ 使用此方法。EF Core 1.x/2.x 使用另一种方法,EF Core 5.0 允许您在两者之间进行选择。为什么?因为当您有多个子集合时,这往往会产生非常低效的查询(执行和处理结果集,因为它传输了大量不必要的数据)。
其次是使用单独的查询——一个用于主结果集,一个用于每个相关的子集合。这个想法很简单。由于通常 PK 和 FK 都被索引,因此数据库可以使用索引(join
无论如何操作都需要)有效地返回按这些列排序的它们,然后它们可以通过提前读取(缓冲)最多一条记录轻松地在客户端合并。
听起来不错,不是吗?有一个小而重要的警告——它需要火星!否则,它必须切换到缓冲模式。这完全违背了IEnumerator
异步版本的想法- 取消概念。您可以在我对如何使用 GetAsyncEnumerator 中止正在运行的 EF Core 查询的回答中看到后者的效果。,最后的建议是启用 MARS。
有关 EF Core 查询的更多信息,请参阅官方 EF Core 文档的拆分查询和查询如何工作(以及基本上整个查询数据)部分。
旁注单独的连接并不是一种真正的选择,特别是如果需要事务级别,如可重复读取。MARS 提供了连接所需的精确抽象。SP 中的 AFAIK 可以同时打开任意数量的游标,因此不确定 ADO 连接层的确切问题是什么,以及为什么 MARS 被认为是需要启用的可选功能,而不仅仅是开箱即用的功能。不过,ORM 可以在适用时尝试在幕后使用单独的连接。EF Core 目前没有。
所以简单回顾一下,如果您不使用延迟加载(可能)并且没有相关集合(不太可能 - 一对多很常见,并且相关集合并不一定意味着导航属性并且Include
- 同样适用到列表和类似成员的预测),那么您就不需要 MARS。否则最好启用它们 - 它们是功能,所以使用它。
归档时间: |
|
查看次数: |
2085 次 |
最近记录: |