EF 4.1代码优先:EF生成的sql和自定义sql之间的区别
我有一个关于实体框架生成的sql和手写sql的问题。在我的项目中,我有一些实体(它们对于这个问题来说并不重要),举一个简单的例子,当我使用这段代码时:
var query = context.Employees.Select(e => new {
PersonalCode = e.PersonelCode,
Fname = e.Person.Fname,
Family = e.Person.Family,
Email = e.Person.Emails
});
生成的sql是这样的:
SELECT
[Project1].[EmployeeID] AS [EmployeeID],
[Project1].[EmployeeID1] AS [EmployeeID1],
[Project1].[PersonID] AS [PersonID],
[Project1].[EmployeeID2] AS [EmployeeID2],
[Project1].[PersonID1] AS [PersonID1],
[Project1].[PersonelCode] AS [PersonelCode],
[Project1].[Fname] AS [Fname],
[Project1].[Family] AS [Family],
[Project1].[C1] AS [C1],
[Project1].[EmailID] AS [EmailID],
[Project1].[Mail] AS [Mail]
FROM ( SELECT
[Extent1].[EmployeeID] AS [EmployeeID],
[Extent1].[PersonelCode] AS [PersonelCode],
[Join1].[PersonID] AS [PersonID],
[Join1].[Fname] AS [Fname],
[Join1].[EmployeeID] AS [EmployeeID1],
[Join3].[PersonID] AS [PersonID1],
[Join3].[Family] AS [Family],
[Join3].[EmployeeID] AS [EmployeeID2],
[Join5].[EmailID1] AS [EmailID],
[Join5].[Mail] AS [Mail],
CASE WHEN ([Join5].[EmailID2] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Employees] AS [Extent1]
LEFT OUTER JOIN (SELECT [Extent2].[PersonID] AS [PersonID], [Extent2].[Fname] AS [Fname], [Extent3].[EmployeeID] AS [EmployeeID]
FROM [dbo].[Persons] AS [Extent2]
LEFT OUTER JOIN [dbo].[Employees] AS [Extent3] ON [Extent2].[PersonID] = [Extent3].[EmployeeID] ) AS [Join1] ON [Extent1].[EmployeeID] = [Join1].[PersonID]
LEFT OUTER JOIN (SELECT [Extent4].[PersonID] AS [PersonID], [Extent4].[Family] AS [Family], [Extent5].[EmployeeID] AS [EmployeeID]
FROM [dbo].[Persons] AS [Extent4]
LEFT OUTER JOIN [dbo].[Employees] AS [Extent5] ON [Extent4].[PersonID] = [Extent5].[EmployeeID] ) AS [Join3] ON [Extent1].[EmployeeID] = [Join3].[PersonID]
LEFT OUTER JOIN (SELECT [Extent6].[EmailID] AS [EmailID2], [Extent6].[PersonID] AS [PersonID], [Extent7].[EmailID] AS [EmailID1], [Extent7].[Mail] AS [Mail]
FROM [dbo].[EmailsForPersons] AS [Extent6]
INNER JOIN [dbo].[Emails] AS [Extent7] ON [Extent6].[EmailID] = [Extent7].[EmailID] ) AS [Join5] ON [Join5].[PersonID] = [Extent1].[EmployeeID]
) AS [Project1]
ORDER BY [Project1].[EmployeeID] ASC, [Project1].[EmployeeID1] ASC, [Project1].[PersonID] ASC, [Project1].[EmployeeID2] ASC, [Project1].[PersonID1] ASC, [Project1].[C1] ASC
但是通过这段代码:
SELECT Employees.PersonelCode, Persons.Fname, Persons.Family, Emails.Mail
FROM Employees
LEFT OUTER JOIN -- or: INNER JOIN
Persons ON Employees.EmployeeID = Persons.PersonID
LEFT OUTER JOIN
EmailsForPersons ON Persons.PersonID = EmailsForPersons.PersonID
LEFT OUTER JOIN
Emails ON EmailsForPersons.EmailID = Emails.EmailID
我会给出相同的结果结果!这些代码有什么区别?哪一个性能更高、速度更快?
I have a question about sql generated by Entity Framework and the hand-writed one. In my project, I have some entities (they aren't important really for this Q), for a simple example, when I use this code:
var query = context.Employees.Select(e => new {
PersonalCode = e.PersonelCode,
Fname = e.Person.Fname,
Family = e.Person.Family,
Email = e.Person.Emails
});
the generated sql is something like this:
SELECT
[Project1].[EmployeeID] AS [EmployeeID],
[Project1].[EmployeeID1] AS [EmployeeID1],
[Project1].[PersonID] AS [PersonID],
[Project1].[EmployeeID2] AS [EmployeeID2],
[Project1].[PersonID1] AS [PersonID1],
[Project1].[PersonelCode] AS [PersonelCode],
[Project1].[Fname] AS [Fname],
[Project1].[Family] AS [Family],
[Project1].[C1] AS [C1],
[Project1].[EmailID] AS [EmailID],
[Project1].[Mail] AS [Mail]
FROM ( SELECT
[Extent1].[EmployeeID] AS [EmployeeID],
[Extent1].[PersonelCode] AS [PersonelCode],
[Join1].[PersonID] AS [PersonID],
[Join1].[Fname] AS [Fname],
[Join1].[EmployeeID] AS [EmployeeID1],
[Join3].[PersonID] AS [PersonID1],
[Join3].[Family] AS [Family],
[Join3].[EmployeeID] AS [EmployeeID2],
[Join5].[EmailID1] AS [EmailID],
[Join5].[Mail] AS [Mail],
CASE WHEN ([Join5].[EmailID2] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Employees] AS [Extent1]
LEFT OUTER JOIN (SELECT [Extent2].[PersonID] AS [PersonID], [Extent2].[Fname] AS [Fname], [Extent3].[EmployeeID] AS [EmployeeID]
FROM [dbo].[Persons] AS [Extent2]
LEFT OUTER JOIN [dbo].[Employees] AS [Extent3] ON [Extent2].[PersonID] = [Extent3].[EmployeeID] ) AS [Join1] ON [Extent1].[EmployeeID] = [Join1].[PersonID]
LEFT OUTER JOIN (SELECT [Extent4].[PersonID] AS [PersonID], [Extent4].[Family] AS [Family], [Extent5].[EmployeeID] AS [EmployeeID]
FROM [dbo].[Persons] AS [Extent4]
LEFT OUTER JOIN [dbo].[Employees] AS [Extent5] ON [Extent4].[PersonID] = [Extent5].[EmployeeID] ) AS [Join3] ON [Extent1].[EmployeeID] = [Join3].[PersonID]
LEFT OUTER JOIN (SELECT [Extent6].[EmailID] AS [EmailID2], [Extent6].[PersonID] AS [PersonID], [Extent7].[EmailID] AS [EmailID1], [Extent7].[Mail] AS [Mail]
FROM [dbo].[EmailsForPersons] AS [Extent6]
INNER JOIN [dbo].[Emails] AS [Extent7] ON [Extent6].[EmailID] = [Extent7].[EmailID] ) AS [Join5] ON [Join5].[PersonID] = [Extent1].[EmployeeID]
) AS [Project1]
ORDER BY [Project1].[EmployeeID] ASC, [Project1].[EmployeeID1] ASC, [Project1].[PersonID] ASC, [Project1].[EmployeeID2] ASC, [Project1].[PersonID1] ASC, [Project1].[C1] ASC
but by this code:
SELECT Employees.PersonelCode, Persons.Fname, Persons.Family, Emails.Mail
FROM Employees
LEFT OUTER JOIN -- or: INNER JOIN
Persons ON Employees.EmployeeID = Persons.PersonID
LEFT OUTER JOIN
EmailsForPersons ON Persons.PersonID = EmailsForPersons.PersonID
LEFT OUTER JOIN
Emails ON EmailsForPersons.EmailID = Emails.EmailID
I'll give the same result! What is difference between these codes? Which one have a higher performance and higher speed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以对这两个查询进行分析和采样,看看哪个性能更好?
另请参阅如何清理和优化优化 WCF OData 服务生成的代码?
EF 生成的 SQL 非常通用,需要在各种情况下工作。无论出于何种原因,它都非常冗长。它通常具有
SELECT [Col1] FROM (SELECT [Col1] ...)
嵌套结构,以及大量用于比较的CAST
语句。这样做是否是为了确保最大的兼容性和最小化某人棘手的查询无法被翻译的可能性,还是因为生成 SQL 的代码更加清晰和简单,我们只能猜测。这是实体框架团队内部做出的设计决策。
坦率地说,我根本不担心这个问题,除非您使用查询分析器并排测试两个查询的性能。我预计两者之间的差异非常小。
如果生成的查询的性能较差,那么最简单的模式是将逻辑编写在存储过程中,并让 EF 调用存储过程。这将所有控制权从 EF 手中夺走,并交到您手中。
You can analysed and sampled the two queries to see which performs better?
See also How to clean & optimise code generated by WCF OData service?
The SQL generated by EF is very generic and needs to work in a variety of situations. For whatever reason, it is very verbose. It often has a
SELECT [Col1] FROM (SELECT [Col1] ...)
nested structure, and lots ofCAST
statements for comparisons.Whether this is done to ensure maximum compatibility and minimum chance of someone's tricky query not being able to be translated, or whether it's done because the code that generates the SQL is much clearer and simpler, we can only guess. It's a design decision made within the Entity Framework team.
Frankly I wouldn't worry about this at all unless you test the two queries side-by-side for performance using query analyser. I would expect very minimal difference between the two.
If the performance is worse for the generated query then the simplest pattern is to write the logic inside a stored procedure and have EF call the stored procedure. This takes all the control away from EF and puts it in your hands.