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使用过程中的两个问题

如何在 ASP.NET 5 中将 Entity Framework 6 与 MySQL 一起使用?

.Net Framework 4.5.2 和 Entity Framework 6 中的两种不同的数据库访问