好大一个坑: EF Core 异步读取大字符串字段比同步慢100多倍

  • 时间:
  • 浏览:0
  • 来源:大发时时彩官网_大发时时彩邀请码_大发时时彩娱乐平台

这四天遇到一另一个奇怪的问題,通过 EF/EF Core 查询数据库波特率奇慢,先是在传统的 ASP.NET 项目中遇到(用的是EF6.0),之后 将该项目迁移至 ASP.NET Core 也是同样的问題(用的是EF Core 2.2.2)。

问題触发的条件是所查询的字段中存储了很大的字符串(有400多万个字符),查询耗时竟然要40s左右(对,是40秒),CPU消耗也很高,2核CPU消耗400%-400%左右,而添加 Dapper 则没你你你是什么问題。

通过 EF Core 的 Debug 日志跟踪发现,耗时居于在执行完 DbCommand 与 dispose DbDataReader 之间:

2019-02-23 15:46:27.026 [Information] Executed DbCommand ("4"ms) [Parameters=[""], CommandType='Text', CommandTimeout='400']"
2019-02-23 15:47:06.859 [Debug] A data reader was disposed.

通过日志跟踪信息看,很容易会怀疑耗时将会居于在 ADO.NET DataReader 读取数据时,但你你你是什么怀疑与 Dapper 查询正常矛盾,怎么让 CPU 消耗高也说明耗时都在总出 在 IO 层面。

之后 在 stackoverflow 上找到了线索 Poor performance when loading entity with large string property using Entity Framework

I had the same issue yesterday. What I did find out is that async operations with Entity Framework is broken or at least very slow. Try using the same operations synchronously

当时都看了你你你是什么线索,有点不相信,异步竟然会引起你你你是什么问題,都在默认都使用异步吗?本来 抱着试试看的心理将代码中的 ToListAsync() 改为 ToList() ,结果却你会大吃一惊,多次测试,查询耗时在 400-4000 ms 之间,快了 400 多倍。

更新

触发你你你是什么问題有 3 个条件:

1)读取的字符串很大

2)使用 DbCommand.ExecuteReaderAsync 异步最好的方法读取

3)调用 ExecuteReaderAsync 时这麼给 behavior 参数传值 CommandBehavior.SequentialAccess

在 Dapper 中这麼总出 问題是将会 Dapper 中设置了 CommandBehavior.SequentialAccess ,详见 Dapper 的源代码 SqlMapper.Async.cs#L945

using (var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false))
{
    //...
}

EF Core 中会总出 你你你是什么问題是将会 EF Core 调用的是 ExecuteReaderAsync(CancellationToken cancellationToken) ,这麼设置 CommandBehavior ,详见 EF Core 的源代码 RelationalCommand.cs#L292

result = new RelationalDataReader(
    connection,
    dbCommand,
    await dbCommand.ExecuteReaderAsync(cancellationToken),
    commandId,
    Logger);

关于 CommandBehavior.SequentialAccess 详见微软官方文档

Provides a way for the DataReader to handle rows that contain columns with large binary values. Rather than loading the entire row, SequentialAccess enables the DataReader to load data as a stream. You can then use the GetBytes or GetChars method to specify a byte location to start the read operation, and a limited buffer size for the data being returned.

猜你喜欢

如果2007年花1千美元买Netflix股票 这笔投资现值9万美元

【TechWeb】1月16日消息,据美国财经媒体CNBC报道,美国视频流媒体巨头Netflix周二提前大选 将对其订阅服务提价13%至18%,这也是Netflix历史上最大幅

2020-01-26

Spring Boot(一):入门篇

构建微服务:Springboot入门篇SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来繁复新Spring应用的初始搭建以及开发过程。该框架使用了特定的

2020-01-26

90后成睡眠特困户: 进口助眠商品消费涨幅118%

站长之家(ChinaZ.com)10月14日消息:如今,有睡眠难题的年轻人没有了少数,90后成睡眠特困户,有90后不想为了睡个好觉,买有有俩个多多60 0元左右的乳胶枕头。某

2020-01-26

容易受煽动 惊被捕前途尽毁

个案一:身份:中三生阿伟(化名)与妈妈“阿伟冇乜主见,同学话乜佢就做乜,呢点我最担心。我怕佢畀人怂慂做违法嘢,想要被拉去坐监!”──阿伟妈妈“佢(妈妈)趁我冲凉,摷我个袋睇有冇

2020-01-26

欧盟峰会英国首相空手回 英内阁拟谋脱欧Plan B

图:文翠珊与欧盟委员会主席容克疑在峰会上有所争执/美联社据法新社及路透社报道:欧盟领导人14日结束了了英语 英语 两日峰会,英国首相文翠珊仍是空手而回。大多数英国政府阁员认为

2020-01-26