【问题标题】:LINQ Query incredibly slow - why?LINQ 查询非常慢 - 为什么?
【发布时间】:2011-10-19 22:19:44
【问题描述】:

我得到了一个非常简单的 LINQ 查询:

List<table> list = ( from t in ctx.table
                     where
                     t.test == someString
                     && t.date >= dateStartInt
                     && t.date <= dateEndInt
                     select t ).ToList<table>();

被查询的表有大约 3000 万行,但列 testdate 被索引。 当它应该返回大约 5000 行时,需要几分钟才能完成。

我还检查了 LINQ 生成的 SQL 命令。 如果我在 SQL Server 上运行该命令,则需要 2 秒才能完成。

这里的 LINQ 有什么问题? 这只是一个非常简单的查询,没有任何连接。

这是 SQL Profiler 显示的查询:

exec sp_executesql N'SELECT [t0].[test]
FROM [dbo].[table] AS [t0]
WHERE ([t0].[test] IN (@p0)) AND ([t0].[date] >= @p1) 
AND ([t0].[date] <= @p2)',
N'@p0 nvarchar(12),@p1 int,@p2 int',@p0=N'123test',@p1=110801,@p2=110804

编辑:

真的很奇怪。在测试时,我注意到它现在要快得多。 LINQ 查询现在需要 3 秒来处理大约 20000 行,这还不错。

更令人困惑的是: 这与我们的生产服务器上的行为相同。一个小时前真的很慢,现在又快了。当我在开发服务器上进行测试时,我没有在生产服务器上进行任何更改。我能想到的唯一问题是两台服务器都是虚拟化的,并且与许多其他服务器共享 SAN。

我怎样才能知道这是否是问题所在?

【问题讨论】:

  • SQL Server 将缓存查询,因此您可能执行的测试不公平。
  • 你看过执行计划了吗?索引是否碎片化?
  • 使用 SQL Server Profiler 查看真正执行的查询。
  • 我不明白的是,我们得到了另一个包含大约 6 亿行的巨大表,并且对该表的查询只需一秒钟(使用 LINQ)。差异从何而来?我从未使用过 SQL Server Profiler,但我现在就试试。
  • table 的构造函数中有什么?它的属性设置器中发生了什么?

标签: c# linq performance datacontext


【解决方案1】:

在指责 LINQ 之前,首先要找出实际延迟发生在哪里。

  • 发送查询
  • 查询的执行
  • 接收结果
  • 将结果转换为本地类型
  • 在 UI 中绑定/显示结果
  • 以及与此过程相关的任何其他事件

然后开始责怪LINQ ;)

【讨论】:

  • 我想知道延迟是从哪里来的,但我不知道怎么做 :) 如何在 SQL Server Profiler 中设置过滤器以仅显示特定表上的操作?服务器上发生的事情太多了。
  • @Dave,使用 SQL Profiler 查看 SQL Server 的出入时间和内容。剥离客户端并使用 Stopwatch 类来计时。
  • @Dave,您希望我如何帮助您处理这种级别的信息?您是否连接到正确的数据库(您是否使用本地副本?)您是否正在监视正确的事件?
  • 好的,我找到了 LINQ 发送的查询。 SQL Profiler 显示的持续时间与我的应用程序中的秒表相同。
  • @Dave,您能否将查询添加到您的问题中?
【解决方案2】:

如果我必须猜测,我会说“参数嗅探”是可能的,即它已经建立并缓存了一个基于一个参数集的查询计划,它对于您当前的参数值来说非常不理想。您可以在常规 TSQL 中使用 OPTION (OPTIMIZE FOR UNKNOWN) 来解决此问题,但没有 LINQ-to-SQL / EF 方法可以解决此问题。

我的计划是:

  1. 使用分析来证明时间正在查询中丢失(而不是具体化等)
  2. 一旦确认,考虑使用直接TSQL方法调用

例如,对于 LINQ-to-SQL,ctx.ExecuteQuery&lt;YourType&gt;(tsql, arg0, ...) 可用于在服务器上抛出原始 TSQL(参数为 {0} 等,如 string.Format)。就个人而言,我更倾向于“dapper”——非常相似的用法,但物化器更快(但它不支持 EntityRef&lt;&gt; 等延迟加载值——这通常是一件坏事,因为它会导致 N+ 1).

即(与小巧玲珑)

List<table> list = ctx.Query<table>(@"
   select * from table
   where test == @someString
   and date >= @dateStartInt
   and date <= @dateEndInt
   OPTION (OPTIMIZE FOR UNKNOWN)",
new {someString, dateStartInt, dateEndInt}).ToList();

或(LINQ-to-SQL):

List<table> list = ctx.ExecuteQuery<table>(@"
   select * from table
   where test == {0}
   and date >= {1}
   and date <= {2}
   OPTION (OPTIMIZE FOR UNKNOWN)",
someString, dateStartInt, dateEndInt).ToList();

【讨论】:

  • @Dave 并且您正在根据 相同的值对其进行测试?好的...testdate完整 DB 类型是什么?例如,test 是否输入为 nvarchar(100)char(20) 等?
  • 是的,完全一样。我跑了几次,并将持续时间与秒表进行了比较。测试是“nvarchar(12)”,日期是“int”。
  • @Dave 他们是常规专栏吗?计算值?持久的计算值? ...?
  • 只是普通的列。实际上,第二个完成的时间大约是普通 linq 查询的两倍。我用返回 4500 行的值对其进行了测试。
  • 真的很奇怪。在测试时,我注意到它现在要快得多。 LINQ 查询现在需要 3 秒来处理大约 20000 行,这还不错。更令人困惑的是:这与我们的生产服务器上的行为相同。一个小时前真的很慢,现在又快了。当我在开发服务器上进行测试时,我没有在生产服务器上进行任何更改。我唯一能想到的问题是两台服务器都是虚拟化的,并且与许多其他服务器共享 SAN。我怎样才能知道这是否是问题所在?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多