实体框架Take语句,导致EF生成无效的SQL查询

时间:2013-06-23 07:48:13

标签: c# performance entity-framework ef-code-first paging

我在EF CodeFirst中使用TakeSkip语句,用于实现Paging(如 Zoran Maksimovic中所述的this post),这些语句导致EF生成sql查询像这样(我的页面大小是100):

 SELECT TOP (100) [Filter1].[Id]                AS [Id],
                  [Filter1].[SendDuration]      AS [SendDuration]
        FROM   (SELECT [Extent1].[Id] AS [Id],               
                       [Extent1].[SendDuration] AS [SendDuration],
                       row_number() OVER (ORDER BY [Extent1].[SendDuration] DESC) AS [row_number]
                       FROM   [dbo].[MyView] AS [Extent1]
                       WHERE  (1293>= [Extent1].[Id])
                )AS [Filter1]
                WHERE  [Filter1].[row_number] > 500
                ORDER  BY [Filter1].[SendDuration] DESC

但是这个sql在sql server中运行时速度很慢,但Boanergecomment中使用row_number < X代替Top(y)导致性能提升。我的意思是,如果我将生成的sql更改为:

     SELECT  [Filter1].[Id]                AS [Id],
                  [Filter1].[SendDuration]      AS [SendDuration]
        FROM   (SELECT [Extent1].[Id] AS [Id],               
                       [Extent1].[SendDuration] AS [SendDuration],
                       row_number() OVER (ORDER BY [Extent1].[SendDuration] DESC) AS [row_number]
                       FROM   [dbo].[MyView] AS [Extent1]
                       WHERE  (1293>= [Extent1].[Id])
                )AS [Filter1]
                WHERE  [Filter1].[row_number] > 500 and [Filter1].[row_number] <= 600
                ORDER  BY [Filter1].[SendDuration] DESC

查询执行时间会更好,更可接受(在某些情况下,更快4或5倍)。 有没有办法强制EF生成第二个Sql而不是第一个Sql?

2 个答案:

答案 0 :(得分:2)

如果没有看到完整的架构等,很难确定,但对我而言,这表明缺少索引 1

使用包含实际执行计划运行查询,并查看SSMS告诉您的内容 - 它通常会建议额外的索引。

我有一个数百万条记录的数据集 - 并且花了大约3天使用LINQpad,SSMS和执行计划的详细分析来优化每个查询。最后,我设法通过添加3个额外的索引来节省大约96%的执行时间。


1 这是一个线索,当您可以限制范围并提高性能时,索引是必需的/将有所帮助 - 因为这表明正在执行扫描而我们不喜欢扫描。

答案 1 :(得分:1)

这是算法查询生成的双重优势:查询与算法一样好。改变的唯一方法是算法决定做一些不同的事情 - 可能使用不同版本的ORM工具。当然,“不同”并不总是与“更好”相同:)

对于非平凡的查询,经验丰富的SQL开发人员将在使用正确的工具(SSMS提供您需要的大部分内容)时 - 通常能够胜过许多生成的查询。当然,经验不足的SQL开发人员最终可能会在查询错误的事情时结束。

大多数ORM提供了将原始SQL查询传递到引擎的选项 - 但这确实会失去可移植性。如果这是一个问题,另一个选择就是存储过程,其中API甚至可以在不同数据库的不同实现上相似。

您需要在此提出的问题是:

  • 我是否真正针对多个数据库提供商?
  • 我很高兴能够持续维护此查询吗?

如果答案为“否”和“是”,您应该可以将原始SQL(可能是T-SQL)查询传递给EF。