1

我在 EF CodeFirst 中使用TakeandSkip语句来实现分页(正如Zoran Maksimovic这篇文章中所说),这些语句导致 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 server 中运行时,这个 sql 太慢了,但是正如Boanerge在他的评论中所说,使用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?

4

2 回答 2

2

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

运行包含实际执行计划的查询,看看 SSMS 告诉你什么——它通常建议一个额外的索引。

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


1这是需要索引的线索/当您可以限制范围并提高性能时会有所帮助 - 因为这表明正在执行扫描并且我们不喜欢扫描......

于 2013-06-23T08:58:41.570 回答
1

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

对于非平凡的查询,经验丰富的 SQL 开发人员在配备正确的工具(SSMS 提供您需要的大部分功能)时,通常能够胜过许多生成的查询。当然,经验不足的 SQL 开发人员最终可能会导致查询做错事

大多数 ORM 提供将原始 SQL 查询传递到引擎的选项——但这确实失去了可移植性。如果这是一个问题,另一种选择是存储过程之类的东西,即使在不同数据库上的不同实现上,API 也可能相似。

您需要在这里问的问题是:

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

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

于 2013-06-23T08:32:07.510 回答