我有这段代码:
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
- 来自 - SELECT
虽然它完全是多余的 - 但SELECT
就足够了。使用EF的代码运行时间超过半分钟,并且该查询超时,尽管表格相当小。
为什么会生成这种过度设计的SQL查询,如何让EF生成更好的查询?
答案 0 :(得分:8)
它通过转换表达式树来生成结果SQL。它似乎过度设计(例如,使用子查询)作为转换完成方式的副作用。 转换的细节是专有的和复杂的,结果不应该是人类可读的。
问题并不完全清楚 - 你正试图解决我认为可能不是问题的问题。尝试将生成的查询与您自己的查询进行比较 - 我猜想查询优化器会做出如此简单优化的简短工作。
我的猜测(这可能是你可以得到的最好的答案,除非LINQ to Entities MS dev出现)是他们正在做的那样:产生最有效的查询,但留下令人头疼的 - 将查询优化到他们已经将数百或数千个工作日放入的位的困难工作:SQL Server中的查询优化器。
答案 1 :(得分:3)
它执行额外的Select
但是选择没有相关费用。您可以查看估算的查询计划,并在其中显示0%
费用。这样做是因为EF与Oracle,SQL服务器等各种RDBMS系统兼容,并确保它可能实现最大兼容性。
但是我确实同意Entity Framework生成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并利用更改跟踪机制,这样可以节省您编写繁琐查询的时间,但至少应该尝试使用纯SQL的Select语句,这使您可以更自由地使用SQL产生。