简体   繁体   English

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

[英]Entity Framework Take statement, cause EF generates unefficient SQL query

I'm using Take and Skip statements in EF CodeFirst, for implementing Paging(as Zoran Maksimovic said in this post ), these statements cause EF generate a sql query like this(my page size is 100): 我在EF CodeFirst中使用TakeSkip语句,用于实现Paging(正如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

but this sql is so slow, when run in sql server, but as Boanerge said in his comment using row_number < X instead of Top(y) cause performance increase. 但是这个sql在sql server中运行时速度很慢,但正如Boanerge在他的评论中所说的那样使用row_number < X而不是Top(y)会导致性能提升。 i mean that if i change the generated sql to: 我的意思是,如果我将生成的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

query execution time will be better and more acceptable(in some cases 4 or 5 time more faster). 查询执行时间将更好,更可接受(在某些情况下,更快4或5倍)。 Is there any way to force EF to generate 2nd Sql instead 1st Sql? 有没有办法强制EF生成第二个Sql而不是第一个Sql?

Without seeing your full schema etc. it's hard to be certain but to me this indicates a missing index 1 . 没有看到你的完整架构等,很难确定,但对我来说,这表明缺少索引1

Run the query with include actual execution plan and see what SSMS tells you - it often suggest an extra index. 运行包含实际执行计划的查询,并查看SSMS告诉您的内容 - 它通常会建议一个额外的索引。

I've got one dataset that is millions of records - and spent about 3 days optimising each query using LINQpad, SSMS and detailed analysis of the execution plan. 我有一个数百万个记录的数据集 - 并且花了大约3天使用LINQpad,SSMS和执行计划的详细分析来优化每个查询。 In the end I managed to save around 96% execution time just by adding 3 extra indexes. 最后,我设法通过添加3个额外的索引来节省大约96%的执行时间。


1 It's a clue that indexing is required/would help when you can restrict the range and improve the performance - as that's indicating that a scan is being performed and we don't like scans... 1这是一个线索,当您可以限制范围并提高性能时,索引是必需的/将有所帮助 - 因为这表明正在执行扫描而我们不喜欢扫描...

This is the double edge of algorithmic query generation: the query is only as good as the algorithm. 这是算法查询生成的双重优势:查询仅与算法一样好。 The only way for that to change is if the algorithm decides to do something different - perhaps with a different version of the ORM tool. 改变的唯一方法是算法决定做一些不同的事情 - 可能使用不同版本的ORM工具。 Of course, "different" is not always the same as "better" :) 当然,“不同”并不总是和“更好”相同:)

For non-trivial queries, an experienced SQL developer will - when armed with the right tools (SSMS provides most of what you would need) - often be able to out-perform many generated queries. 对于非平凡的查询,经验丰富的SQL开发人员 - 如果配备了正确的工具(SSMS提供了您需要的大部分内容) - 通常能够胜过许多生成的查询。 Of course, a less experienced SQL developer may end up with the query doing the wrong thing . 当然,经验不足的SQL开发人员最终可能会遇到错误的查询。

Most ORMs offer the option to pass a raw SQL query into the engine - this does lose portability, though. 大多数ORM提供了将原始SQL查询传递到引擎的选项 - 但这确实会失去可移植性。 If that is a problem, another option is things like stored procedures, where the API could be similar even on different implementations on different databases. 如果这是一个问题,另一个选项就是存储过程,其中API甚至可以在不同数据库的不同实现上相似。

The questions you need to ask here are: 您需要在这里提出的问题是:

  • do I genuinely target more than one database provider? 我真的针对多个数据库提供商吗?
  • am I happy to own the ongoing maintenance of this query? 我很高兴能够持续维护此查询吗?

If the answers as "no" and "yes", you should be ok to just pass a raw SQL (presumably T-SQL) query to EF. 如果答案为“否”和“是”,您应该可以将原始SQL(可能是T-SQL)查询传递给EF。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM