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

问题描述 投票:0回答:2

我在EF CodeFirst中使用

Take
Skip
语句来实现分页(如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在sql server中运行时非常慢,但是正如Boanerge在他的comment中所说,使用

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?

c# performance entity-framework pagination ef-code-first
2个回答
2
投票

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

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

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


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


1
投票

这是算法查询生成的双刃剑:查询的好坏取决于算法。改变这种情况的唯一方法是算法决定做一些不同的事情——也许使用不同版本的 ORM 工具。当然,“不同”并不总是等同于“更好”:)

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

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.