3

我有这个代码:

DbSet<TableName> table = ...// stored reference

var items = from n in table where
            n.Name.ToUpper().Contains(searchString.ToUpper().Trim())
            select n;
WriteToLog( items.ToString() );

最后一行输出生成的 SQL。这是我得到的:

SELECT 
    [Extent1].[Name] AS [Name],
    // all the other columns follow
FROM (SELECT 
  [TableName].[Name] AS [Name],
  // all the other columns follow
FROM [dbo].[TableName] AS [TableName]) AS [Extent1]
WHERE ( CAST(CHARINDEX(LTRIM(RTRIM(UPPER(@p__linq__0))), UPPER([Extent1].[Name])) AS int)) > 0

你看,有SELECT-from-SELECT虽然它完全是多余的 - 一个SELECT就足够了。尽管表相当小,但使用 EF 的代码运行时间超过半分钟并在该查询上超时。

为什么会生成这个过度设计的 SQL 查询,如何让 EF 生成更好的查询?

4

2 回答 2

8

它通过转换表达式树来生成结果 SQL。作为完成该转换的方式的副作用,它似乎过度设计(例如,使用子查询)。转换的细节是专有的和复杂的,结果不应该是人类可读的。

这个问题并不完全清楚 - 你正在尝试解决一个我认为可能不是问题的问题。尝试将生成的查询与您自己的查询进行比较 - 我猜查询优化器会缩短如此简单的优化工作。

我的猜测(这可能是你可以在这里得到的最好的答案,除非出现 LINQ to Entities MS 开发人员)是他们正在这样做:生成最有效的查询,但留下了令人头疼的困难工作将查询优化到他们已经投入了数百或数千个工作日的位置:SQL Server 中的查询优化器。

于 2012-10-09T12:04:32.480 回答
3

它做了额外的事情,Select但 Selects 没有相关的成本。您可以看到估计的查询计划,它会显示其中0%的成本。这样做是因为 EF 与各种 RDBMS 系统(如 Oracle、SQL 服务器)兼容,并且为了确保最大的兼容性,它可能会这样做。

但是我确实同意实体框架生成 UGLY sql。您提供的示例是一个非常简单的 Linq 查询,当您的查询开始变得复杂时,您会看到更多的丑陋。

1)虽然这可能会或可能不会回答您的答案,但我会说使用像 PetaPoco 这样的微型 ORM:

https://github.com/toptensoftware/PetaPoco

或 Dapper.Net

https://github.com/SamSaffron/dapper-dot-net

我一直在我的一个项目中使用它,我对使用普通 Ado.Net 获得的原始速度完全满意。

2)我的第二个建议是总是对至少 Select语句使用存储过程。对于插入、更新和删除,您可能应该使用 EF 并利用更改跟踪机制,这样可以节省您编写繁琐查询的时间,但至少对于 Select 语句,您应该尝试使用纯 SQL,这样您就可以更自由地了解 SQL 是什么生成。

于 2012-10-09T12:52:25.547 回答