【问题标题】:performance of LINQ queries against the SQL equivalent针对 SQL 等效项的 LINQ 查询性能
【发布时间】:2011-09-29 17:23:12
【问题描述】:

我目前正在与工作人员就 LINQ 查询对 SQL 等效项的性能进行辩论。

有没有人对此进行过/看过任何科学测试?

如果不是这样,关于您出于性能原因不得不用 SQL 查询替换 LINQ 的轶事证据将帮助我证明我的观点。

【问题讨论】:

  • 你对这场辩论有什么看法?不应该使用 LINQ 查询,因为它们速度较慢?您应该分析您的 LINQ 查询,以防您可以通过 SQL 查询提高性能?

标签: .net sql linq performance


【解决方案1】:

我对此略有不同;在进行分析时(使用我们的shiny profiler),我们注意到 LINQ(在这种情况下为 SQL)正在为基本查询生成 TSQL,并且该操作在 DB 服务器上运行得非常快(0.5ms 等) - 但是,实际的查询操作花费的时间要长得多(在某些情况下,对于相同的 0.5ms 查询需要 20ms+)。那么时间在哪里呢?您可能会想到“查询翻译”,但不是;我们也有很多 ExecuteQuery<T> 代码(即您在哪里手动编写 TSQL),而这完全相同。事实证明,在 materializeridentity map 之间的某个地方正在浪费大量时间。

所以;我们编写了自己的物化器,它几乎可以替代ExecuteQuery - 因此诞生了dapper

在更多的 LINQ 方面,它通常可以为 简单 查询生成 TSQL,但对于任何复杂的事情,我通常更信任手工编码的 TSQL。以一个案例为例,我有一个复杂的查询,涉及组、跳过和接受。它表现不佳。当我使用 ROW_NUMBER() 等手动编写时,相同的结果占用了 4% 的“stats IO”和总时间。

我目前对 LINQ 的看法是 ORM 工具使数据变异变得轻而易举,但对于 查询,我倾向于使用 小巧玲珑。具有讽刺意味的是,LINQ 中的 Q 是“查询”。

【讨论】:

    【解决方案2】:

    在 LINQ2SQL 或 EF 中的 LINQ 需要有一个通用的规则集来说明如何将 LINQ 查询转换为 SQL,从而引入了一个抽象级别。这种抽象有时会导致语句不是最优的。手动编写 SQL 语句可让您根据具体情况对其进行调整。
    由此得出的结论是,SQL 的速度更有可能更快,尤其是在复杂的场景中。但这并不意味着每个 LINQ 查询都比其等效的 SQL 查询慢。
    我将 EF 1 与 Oracle 结合使用的经验支持这一点。

    【讨论】:

    • 有趣的是,我们看到了另一面;即使 LINQ 在生成查询方面做得很好,我们也遇到了抽象本身引入与实际查询或翻译无关开销的问题。写在答案中......
    【解决方案3】:

    SQL 查询更好的一个更明显的例子是更新/删除批处理。 LINQ-To-SQL 中没有内置工具来处理多个更新或删除,除了逐条处理记录,这会为每条记录生成单独的查询。

    var myRecords = myContext.Books.Where(b => b.Author = "Bob");
    foreach (var rec in myRecords)
        myContext.Books.DeleteOnSubmit(rec);
    myContext.SubmitChanges()  // generates delete statement for each record.
    

    在一般情况下,LINQ 经过优化以生成非常高效的查询,并且有时可以生成比使用 SQL 编写它的直观方式更好的查询。但是,总会有例外情况,即 LINQ-to-SQL 语句的效率不如手动编写的 SQL 查询。

    【讨论】:

      【解决方案4】:

      LinqToSql 是 ADO.Net 之上的一个层。因此,如果您将 ADO.Net 与 Sql 查询一起使用,您将比 LinqToSql“更快”(通过不做 LinqToSql 所做的那些额外事情)。

      同样的论点(当性能是唯一标准时)可以针对 .Net 和机器代码进行。 .Net IL 最终是 JIT 到 Machine 的,如果你一开始就编写 Machine,你会更快。

      这里有几个重要的场景:

      • 如果您的查询是低 IO 并返回大量数据进行具体化,LinqToSql 将比原始 sql 花费更多的时间。另一方面,您最终会得到 Customer 实例而不是 DataRows。
      • 如果您的查询是高度动态的,以至于您永远不会两次发出相同的 sql 文本,那么您总是会产生查询翻译成本。 Sql 查询会更快(尤其是如果你不计算 sql 文本的构造)。

      以下是几个无关紧要的场景:

      • 如果您的查询是大量的数据库 IO(报告样式),您不会注意到 LinqToSql 抽象的额外客户端 CPU 成本。
      • 如果您的查询是重复的(使用不同参数的相同查询),则可以通过使用 CompiledQuery 来减轻 LinqToSql 抽象的大部分成本。

      【讨论】:

        【解决方案5】:

        请查看其他问题:LINQ-to-SQL vs stored procedures?

        在我看来,linq 几乎可以在各个方面使用。在极少数情况下,当您非常擅长 sql 并且确实想提高性能时,请改用原始 sql。

        【讨论】:

          【解决方案6】:

          当您运行 LINQ 查询时,LINQ 会生成 T-SQL 代码来执行您的查询。您可以运行 SQL Server Profiler 来了解查询的外观。我过去做过,生成的 T-SQL 看起来很干净。

          我不能直接谈论性能,因为我没有运行任何数字,但我看到的一件事是,除非您在表中使用 rowversion 列进行 LINQ 查询,否则您最终会得到每一列在包含在 WHERE 子句中的表中,这是作为 LINQ 内置乐观并发检查的一部分完成的。使用 rowversion 列允许 LINQ 仅使用该列进行此检查,并使 T-SQL 更简洁、性能更高。

          【讨论】:

            【解决方案7】:

            今年早些时候,我提交了一份针对 Linq2Sql 在单个事务集中插入许多记录时的性能的错误报告。每个单独的插入处理的时间越来越长,因为 Linq2Sql 必须检查关系 - 无论如何数据库服务器都会检查。

            您可以在https://connect.microsoft.com/VisualStudio/feedback/details/637841/linq-to-sql-shows-progressively-worse-performance-as-the-transaction-set-grows查看错误报告

            点击节目详情,我附上了一些性能数据。

            有趣的是,微软的回答是他们不打算提高 Linq2Sql 的性能,我应该使用 ADO.Net,这是我已经决定要做的。

            此时我的底线是我喜欢使用 Linq2Sql 进行查询,但不会将其用于插入或更新。我还喜欢 Linq2Sql 会为我从我的外键中填充记录,而无需编写单独的查询。

            至于复杂的查询 - 我大约 50% 使用 Linq2Sql 和大约 50% 的存储过程。 我从不使用内联 SQL,因为我更喜欢使用强类型的方法。所以对于简单的查询,Linq2Sql 的简单性 100% 胜过 ADO.Net。

            【讨论】:

              【解决方案8】:

              一般来说,根据我的经验,EF4.1 或 LINQtoSQL 的问题不是 LINQ,而是编码器。

              开发人员通常不知道如何编写高效查询或如何编写高效且可扩展的数据库访问(即他们非常了解 VB 或 C#,但不了解 SQL),这表明他们如何构建查询。那时,他们是否使用 LINQ 并不重要。

              当应用程序在开发中运行良好(开发数据库有几十万行数据)但在生产中表现不佳(数百万行数据)时,真正出现这种情况的地方。开发人员立即指出它在开发中运行良好,所以一定是数据库出了问题,而不是他们的代码。开发人员和 DBA 之间的战争就是这样开始的。

              虽然我真的很喜欢 LINQ,但您通常最好将查询移动到存储过程中,这样您就可以调整和调整您的数据访问,而不必为每个次要的应用程序执行完整的开发-测试-QA-发布周期更新。

              【讨论】:

                猜你喜欢
                • 2012-08-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-05-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多