C# LINQ或实体框架创建无界SQL语句
我致力于应用程序的速度优化,我发现LINQ(或EF)正在为我创建一些奇怪的SQL,但运行速度很慢 下面是一些代码:C# LINQ或实体框架创建无界SQL语句,c#,entity-framework,linq-to-entities,sql-optimization,C#,Entity Framework,Linq To Entities,Sql Optimization,我致力于应用程序的速度优化,我发现LINQ(或EF)正在为我创建一些奇怪的SQL,但运行速度很慢 下面是一些代码: SomeList.AddRange(_databaseView .Select(l=> new SomeViewModel { Date = l.Date,
SomeList.AddRange(_databaseView
.Select(l=> new SomeViewModel
{
Date = l.Date,
Details = l.Details,
Level = l.LevelName,
Id = l.ViewID,
Message = l.Message,
ProjectName = l.projectName,
StatusId = l.StatusID,
StatusName = l.StatusName
})
.Skip(50)
.Take(25));
理论上,它应该创建一个SQL语句,该语句需要25条记录,但profiler为它显示了以下SQL:
SELECT [Extent1].[Date] AS [Date],
[Extent1].[ID] AS [ID],
[Extent1].[LevelID] AS [LevelID],
[Extent1].[StatusID] AS [StatusID],
[Extent1].[projectName] AS [projectName],
[Extent1].[LevelName] AS [LevelName],
[Extent1].[StatusName] AS [StatusName],
[Extent1].[Message] AS [Message],
[Extent1].[Details] AS [Details],
[Extent1].[LogViewID] AS [LogViewID]
FROM (SELECT [v_MyView].[Date] AS [Date],
[v_MyView].[ProjectID] AS [ProjectID],
[v_MyView].[LevelID] AS [LevelID],
[v_MyView].[StatusID] AS [StatusID],
[v_MyView].[projectName] AS [projectName],
[v_MyView].[LevelName] AS [LevelName],
[v_MyView].[StatusName] AS [StatusName],
[v_MyView].[Message] AS [Message],
[v_MyView].[Details] AS [Details],
[v_MyView].[ViewID] AS [ID]
FROM [dbo].[v_MyView] AS [v_MyView]) AS [Extent1]
\u databaseView是一个IQueryable对象,我的所有排序和筛选逻辑都是在它上面完成的。
以下是我的一些想法:
如果我不做任何过滤,SQL是正常的,选择TOP(25)。但每当我做过滤的时候,有些事情就会搞砸。以下是我的一个过滤器的代码:
if (Filters.ProjectName != null && Filters.ProjectName[0] != 0) // check if "all" is not checked
_databaseView = Filters.ProjectName
.Join(_databaseView, f => f, l => l.ProjectID, (f,l) => new SomeViewModel
{
Date = l.Date,
Details = l.Details,
LevelName = l.LevelName,
ViewID = l.ViewID,
Message = l.Message,
projectName = l.projectName,
StatusID = l.StatusID,
StatusName = l.StatusName
})
.AsQueryable();
这是没有任何限制的。如何使LINQ-EF生成一些好的SQL
提前谢谢 实际更改正在使用的SQL的唯一方法是编写自己的SQL并使用它,而不是使用生成的SQL 您是指LINQ中未转换为SQL的Skip和Take部分。我认为这是因为你做LINQ的方式 试试像这样的东西
(From l In DataBaseView Select new SomeViewModel
{
Date = l.Date,
Details = l.Details,
Level = l.LevelName,
Id = l.ViewID,
Message = l.Message,
ProjectName = l.projectName,
StatusId = l.StatusID,
StatusName = l.StatusName
}).Skip(50).Take(25)
取而代之,看看它是否会对生成的代码产生影响
< >强> >编辑<强>,我错过了一部分,你说它应该是SQL,需要25个记录。 < P>如果你不能用适当的索引来获得SQL的足够好,那么你可以试着写一个存储过程并从LINQ调用它。< P> LINQ解析器,绝对要考虑<代码>跳过< /代码>。
在LINQ to Entities查询中采用
方法并生成正确的表达式树,然后对象服务将表达式树转换为命令树,该命令树将传递给数据库提供程序以生成特定的SQL查询。
在这种情况下,这两种方法影响生成的SQL,其中[Extent1].[row_number]>50和
分别为Skip
和Take
选择TOP(25)
。
现在,您确定在探查器中查看的跟踪是正确的吗?我建议在转到探查器之前先编写以下代码,然后通过代码调试并检查sql变量的值来查看该方法:
var query = _DatabaseView.Select(l=> new SomeViewModel {
Date = l.Date,
Details = l.Details,
Level = l.LevelName,
Id = l.ViewID,
Message = l.Message,
ProjectName = l.projectName,
StatusId = l.StatusID,
StatusName = l.StatusName})
.Skip(50)
.Take(25));
string sql = (query as ObjectQuery).ToTraceString();
尝试在选择之前移动跳过和执行。您没有说明
\u DatabaseView
是什么,但根据您的结果,我猜测它不是对象查询。这可以解释你的问题<代码>对象查询
将转换为SQL<代码>IEnumerable.Skip()不会。对可枚举项调用AsQueryable()
,不足以实现这一点
例如,这:
var foo = MyObjectContext.SomeEntitySet.AsEnumerable().AsQueryable().Take(10);
…不会将顶部
放在SQL中
但这是:
var bar = MyObjectContext.SomeEntitySet.Take(10);
。。。威尔
再一次:您还没有说什么是
\u DatabaseView
。直接在ObjectContext
上尝试此操作,您将看到它是有效的。错误在您用来分配\u DatabaseView
的代码中,您没有向我们展示。我已经为此编写了一些存储过程,并且所有索引都已设置。。。因此,剩下的唯一问题是正确的跳过-执行逻辑。您可以非常轻松地将分页添加到存储过程中。在ROW_NUMBER()函数中使用一个通用的表表达式。这里没有必要,而且会损害可组合性。我更愿意保持分页。这样我可以让我的建筑更干净。我做到了。。。你甚至无法想象我放了多少地方=)最后有没有运气驯服EF?确切地说,\u DatabaseView
是什么?是的,这里肯定是这样的。不_DatabaseView是一个IQueryable对象。我甚至在每次排序、筛选的最后都做了asqueryable()。。。。所以它是100%可读取的。也许我不够清楚<代码>AsQueryable()无法解决此问题。我将为您澄清答案。我在这里找到了一些类似的代码:这段代码在IEnumerable上完成所有操作。@Nazar,不,Troy Goode的PagedList
类不是这样工作的。仔细阅读代码。我对这段代码非常熟悉,它并不是“在IEnumerable
上做所有事情”