【发布时间】:2021-06-18 21:20:04
【问题描述】:
我有一个包含三个表的数据库,我正在制作一个程序,该程序将选择并需要同时显示所有三个表的结果。
为了加快记录的获取速度,我决定使请求异步,以便它们可以同时发生。
由于您不能对同一个数据库上下文执行多个并发操作,因此我只实例化总共三个上下文,并在每个上下文上启动一个 Linq 查询“ToListAsync()”。
但是发生了一些奇怪的事情(对我来说)——异步版本并不比同步版本快。无论我是使用“.ToListAsync()”异步获得结果还是使用“.ToList()”同步获得结果,它们都需要相同的时间。使用同步版本,第一个操作大约需要 2 秒才能完成,而第二个大约需要 170 毫秒,第三个大约需要 90 毫秒。我想某种执行计划或缓存或建立连接是什么使第一个请求需要很多时间,而其他请求几乎立即完成,但我想知道为什么会发生这种情况以及是否有办法做到这一点快点。
忘了提到异步版本需要相同的时间 - 2 秒。
相关代码:
int maxRecords = 10;
var resultsTableOne = dbContext.tableOne.Where(log =>
log.DateUtc >= dateFrom || dateFrom == null)
&& (log.DateUtc <= dateTo || dateTo == null))
.OrderByDescending(log => log.Id).Take(maxRecords).ToList();
var resultsTableTwo = dbContext.tableTwo.Where(log =>
log.DateUtc >= dateFrom || dateFrom == null)
&& (log.DateUtc <= dateTo || dateTo == null))
.OrderByDescending(log => log.Id).Take(maxRecords).ToList();
var resultsTableThree = dbContext.tableThree.Where(log =>
log.DateUtc >= dateFrom || dateFrom == null)
&& (log.DateUtc <= dateTo || dateTo == null))
.OrderByDescending(log => log.Id).Take(maxRecords).ToList();
这里简化了选择条件。对于异步版本,“ToList”被替换为“ToListAsync”,它返回一个任务,在此处显示的代码之后调用“GetAwaiter().GetResult()”(并且“dbContext”被替换为三个单独的实例)。
附:
同步版本的结果与一个和三个 DbContext 相同。 IE。无论是在同一个实例上执行所有三个操作还是在自己的实例上执行所有三个操作都需要相同的时间。
【问题讨论】:
-
你能分享你的代码吗?
-
@smoksnes,哦,是的,抱歉 - 现在已编辑。
-
In order to speed up the getting of records为此,修复查询和索引。并发执行不会使服务器的磁盘或 CPU 运行得更快,或者网卡的带宽增加一倍。 为什么查询很慢?多次执行错误的查询会使其变慢而不是变快。如果查询没有合适的索引,如果长寿命事务和连接阻塞它,如果缺少索引导致表级锁,并发查询只会增加阻塞和IO延迟跨度> -
dateUtc是否已编入索引?是Id?如果不是,每个查询最终都会扫描(并锁定)整个表以查找匹配的行。log.DateUtc >= dateFrom || dateFrom == null???这是一个错误,导致执行计划错误。如果您不想使用dateFrom过滤器,只需省略不要使用Where子句。仅此一项就可以强制所有查询扫描整个表,而不是使用DateUtc上的任何索引。这种包罗万象的查询的原因是explained here -
@user14092802 如果您不能使用索引,就无法加快速度。故事结局。第一个查询总是会比较慢,因为它会扫描整个表。后续查询总是会更快,因为数据被缓存直到服务器清除缓存。这是查询和数据库设计的问题,而不是服务器的问题。并发执行不会使原本很慢的查询变得更快
标签: c# database entity-framework asynchronous