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

  • 时间:
  • 浏览:0
  • 来源:大发快3_快3在线稳定计划_大发快3在线稳定计划

这半年遇到一个 奇怪的难题报告 ,通过 EF/EF Core 查询数据库速率奇慢,先是在传统的 ASP.NET 项目中遇到(用的是EF6.0),本来我将该项目迁移至 ASP.NET Core 也是同样的难题报告 (用的是EF Core 2.2.2)。

难题报告 触发的条件是所查询的字段中存储了很大的字符串(有1000多万个字符),查询耗时竟然要40s左右(对,是40秒),CPU消耗也很高,2核CPU消耗1000%-1000%左右,而上加 Dapper 则没这人难题报告 。

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

2019-02-23 15:46:27.026 [Information] Executed DbCommand ("4"ms) [Parameters=[""], CommandType='Text', CommandTimeout='1000']"
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() ,结果却你要大吃一惊,多次测试,查询耗时在 1000-10000 ms 之间,快了 1000 多倍。

更新

触发这人难题报告 有 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.

猜你喜欢

全球比特币谷歌搜索量最大城市TOP10:第一名竟然是它

图片版权所属:站长之家今日块讯(ChinaZ.com)6月12日消息:据Bitcoinist报道,比特币经济学家TuurDemeester发布推文否认了“比特币”谷歌搜索量最多

2020-01-21

乖仔被「洗腦」 打母稱「光復屋企」

圖:暴徒四處設路障堵路,阻礙救護車救人李偉孝曾做青少年義工,當提到現時學生暴徒年齡不斷下降,僅得十一、二歲都參與暴亂,他難過得兩度落淚。李Sir感慨政客煽動,暴力氛圍滲透到每個

2020-01-21

秀婉的江南园林,最有韵味的中国风

我能发布    发布日期:2018-06-0409:37:41核心提示:中国古建筑的美,体现在秀婉的江南园林之中▼亭台飞檐,廊桥蜿蜒▼奇石秀水,移步换景▼拱门营发名者中国古建筑

2020-01-21

如龙0真岛吾朗支线任务怎么做

更新时间:2018-08-0809:56:12来源:斗蟹游戏编辑:我还没想好如龙0真岛吾朗支线任务缘何做?还不清楚的玩家不妨来看看小编为亲戚亲戚大伙带来的如龙0真岛吾朗全支线任

2020-01-21

魔兽世界怀旧服怎么收费?国服采用点卡还是月卡收费

魔兽世界怀旧服如果 在8月27日上线,玩家们十分关心怀旧服的收费依据,是点卡收费还是月卡收费,这里当当我们来看下具体的介绍。暴雪曾表示怀旧服会有并是不是生活收费依据,即经

2020-01-21