博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
好大一个坑: EF Core 异步读取大字符串字段比同步慢100多倍
阅读量:7085 次
发布时间:2019-06-28

本文共 2034 字,大约阅读时间需要 6 分钟。

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

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

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

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

通过日志跟踪信息看,很容易会怀疑耗时可能发生在 ADO.NET DataReader 读取数据时,但这个怀疑与 Dapper 查询正常矛盾,而且 CPU 消耗高也说明耗时不是出现在 IO 层面。

后来在 stackoverflow 上找到了线索

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() ,结果却让人大吃一惊,多次测试,查询耗时在 100-500 ms 之间,快了 100 多倍。

更新

触发这个问题有 3 个条件:
1)读取的字符串很大
2)使用 DbCommand.ExecuteReaderAsync 异步方法读取
3)调用 ExecuteReaderAsync 时没有给 behavior 参数传值 CommandBehavior.SequentialAccess

在 Dapper 中没有出现问题是因为 Dapper 中设置了 CommandBehavior.SequentialAccess ,详见 Dapper 的源代码

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 的源代码

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.

转载于:https://www.cnblogs.com/dudu/p/10423126.html

你可能感兴趣的文章
在Azure中部署Kubernetes容器集群
查看>>
滨湖区胡埭建智能交通缓解交通压力
查看>>
《深度学习:Java语言实现》一一第2章 机器学习算法——为深度学习做准备
查看>>
坚持做创业护卫队的770天
查看>>
《ANSYS Workbench 14有限元分析自学手册》——导读
查看>>
OC之构造方法
查看>>
AppleWatch开发入门二——界面布局
查看>>
6个你必须用到AJAX的地方与6个不必用到的地方
查看>>
OpenExpressApp 框架结构(2)
查看>>
[总结]无线测试
查看>>
⑫云上场景:筋斗云,基于分布式云服务器的深度挖掘
查看>>
Waiting Auto-INC LOCK导致死锁
查看>>
wake-up signal SIGALRM from alarm() or setitimer(). SIG_DFL & SIG_IGN
查看>>
HTTP/2 对 Web 性能的影响(上)
查看>>
react更新state的时候要返回一个全新的引用或者值
查看>>
flex实战
查看>>
Android 高仿腾讯新闻视频切换效果
查看>>
只有程序员才能看懂的15个瞬间
查看>>
Mybatis入门学习---使用注解开发
查看>>
影响网站关键词排名的因素
查看>>