Entity Framework 6 MySQL - 与 MySQL 引擎的性能差异
Posted
技术标签:
【中文标题】Entity Framework 6 MySQL - 与 MySQL 引擎的性能差异【英文标题】:Entity Framework 6 MySQL - performance difference vs MySQL engine 【发布时间】:2017-02-19 20:20:28 【问题描述】:因此,有一些帖子抱怨 Entity Framework 6 的 mysql 插件的性能。然而,其中大部分似乎归结为它生成了错误的 SQL。我遇到了这个问题,但这似乎是由于插件本身造成的性能滞后。
这是我在 LINQ 中的查询:
List<Address> matches = _rep.GetAddresses(s => s.AddressKey == cleanAddress).ToList();
在存储库中 (_rep
) 我有这个:
public IQueryable<Address> GetAddresses(Expression<Func<Address, bool>> query)
//var foo = Addresses.AsNoTracking().Where(query);
//var bar = foo.ToString();
return Addresses.AsNoTracking().Where(query);
所以我已经在使用 AsNoTracking 来尝试提高性能。注释掉的行在那里,所以我可以看到正在生成的 SQL,结果是:
SELECT
`Extent1`.`AddressId`,
`Extent1`.`AddressKey`,
`Extent1`.`NameKey`,
`Extent1`.`Title`,
`Extent1`.`Forename`,
`Extent1`.`Surname`,
FROM `Addresses` AS `Extent1`
WHERE (`Extent1`.`AddressKey` = @p__linq__0)
OR ((`Extent1`.`AddressKey` IS NULL) AND (@p__linq__0 IS NULL))
足够简单。值得注意的是,AddressKey 是一个带有索引的 varchar(255) 列。
现在,事情就是这样。如果我将该查询插入 MySQL 工作台并运行它(使用不同的值 @p__linq__0
),它甚至不会注册运行时间。它将持续时间列为 0.000 秒。
但是,在我的查询周围放置一个秒表并记录执行 Linq 所花费的时间大约为 0.004 秒。您可能认为差别不大,但这是运行此代码数百万次的速度关键型应用程序的一部分。很快就会加起来。
我对后面的 upsert 代码块有同样的问题。在工作台中本地运行,不到一毫秒。同样,通过 EF,它需要 3-4 毫秒。
我认为这归结于 EF MySQL 插件中的弱设计是否正确?如果是这样,如果我尝试将其更改为通过存储过程运行或直接使用ExecuteSqlCommand()
提交 SQL,我可以假设我会遇到同样的问题吗?
还有什么我可以尝试消除这种性能滞后的吗?
【问题讨论】:
您是指通过多次调用测量的平均时间,还是仅使用单个调用(可能是第一次调用有额外开销)? @IvanStoev EF 记录的时间平均为 1k 次调用。 SQL 比较是几个单一的调用。我改变了它每次搜索的密钥,以尝试模仿 EF 在实际操作中所做的事情。 嗯,这只是一个猜测,但它实际上可能是 EF 查询执行/实现过程的开销,换句话说,与 MySQL 插件无关。您可以使用SqlQuery 甚至普通的DbReader
来衡量问题是否出在 EF 和/或 MySQL 插件中,但老实说,我认为您的要求/期望太高了。
【参考方案1】:
运行生成的查询和运行 LINQ 表达式之间存在很大差异。
让我们看看Entity Framework是做什么的
将 LINQ 表达式转换为 DbExpression
这部分有时会比运行查询本身花费更多时间。在某些情况下,如果有多个包含,我看到性能差到几百毫秒。
生成查询或从缓存中获取
第一次生成 SQL Query 可能需要一些时间,但子序列调用将采用从缓存中生成的查询。
缓存使用之前生成的 DbExpression 来创建缓存键。
执行查询
服务器延迟 + 运行查询的时间
对象实现
是时候创建实体了。通常非常快,因为您使用了 AsNoTracking,因此需要跟踪它们。
我可能是错的,但我猜你的大部分时间都是在将 LINQ 表达式转换为 DbExpression 时花费的。
您可以通过验证生成查询所花费的时间来轻松验证它,而无需通过 ToTraceString 方法执行它。注意,直接使用TraceString的时候,不计算MySQL Interceptor所用的时间,但至少可以粗略估计一下时间。
这里是一个 ToTraceString 扩展方法的例子(我没有测试过):Obtain ToTraceString
【讨论】:
以上是关于Entity Framework 6 MySQL - 与 MySQL 引擎的性能差异的主要内容,如果未能解决你的问题,请参考以下文章
在 Entity Framework 6 中使用 MySQL 和 MSSQL
如何将 MySQL 与 .NET Core 3 和 Entity Framework 6 集成
Entity Framework 6 和 mysql TableDetails 强类型异常
Entity Framework 6 Code First +MVC5+MySql/Oracle使用过程中的两个问题