【问题标题】:'LINQ query plan' horribly inefficient but 'Query Analyser query plan' is perfect for same SQL!“LINQ 查询计划”效率极低,但“查询分析器查询计划”非常适合相同的 SQL!
【发布时间】:2011-01-19 14:11:56
【问题描述】:

我有一个生成以下 SQL 的 LINQ to SQL 查询:

exec sp_executesql N'SELECT COUNT(*) AS [value]
FROM [dbo].[SessionVisit] AS [t0]
WHERE ([t0].[VisitedStore] = @p0) AND (NOT ([t0].[Bot] = 1)) AND 
([t0].[SessionDate] > @p1)',N'@p0 int,@p1 datetime',
@p0=1,@p1='2010-02-15 01:24:00'

(这是从 SQL Server 2008 上的 SQL Profiler 获取的实际 SQL。)

当我在Query Analyser 中运行此 SQL 时生成的查询计划是完美的。 它使用包含VisitedStoreBotSessionDate 的索引。 查询立即返回。

但是,当我从 C#(使用 LINQ)运行此程序时,使用了不同的查询计划,该计划效率非常低,甚至在 60 秒内都不会返回。该查询计划试图对包含几百万行的集群主键进行键查找。它没有机会返回。

但我无法理解的是,正在运行完全相同的 SQL - 无论是从 LINQ 内部还是从查询分析器内部,但查询计划却不同。

我已经多次运行这两个查询,现在它们独立于任何其他查询运行。日期是 DateTime.Now.AddDays(-7),但我什至硬编码了该日期以消除缓存问题。

我可以在 LINQ to SQL 中更改什么来影响查询计划或尝试进一步调试吗?我很困惑!

【问题讨论】:

标签: sql-server linq-to-sql


【解决方案1】:

切换到存储过程,相同的 SQL 工作正常。真的很想知道发生了什么,但现在不能再花时间在这上面了。幸运的是,在这种情况下,查询不是太动态。

希望这至少可以帮助与我在同一条船上的任何人

【讨论】:

    【解决方案2】:

    这是一个比较常见的问题,当我第一次看到它时也让我感到惊讶。首先要做的是确保您的统计数据是最新的。您可以通过以下方式检查统计年龄:

    SELECT 
        object_name = Object_Name(ind.object_id),
        IndexName = ind.name,
        StatisticsDate = STATS_DATE(ind.object_id, ind.index_id)
    FROM SYS.INDEXES ind
    order by STATS_DATE(ind.object_id, ind.index_id) desc
    

    应在每周维护计划中更新统计信息。要快速修复,请发出以下命令来更新数据库中的所有统计信息:

    exec sp_updatestats
    

    除了统计数据之外,您还可以查看SET options。它们在查询分析器和您的 Linq2Sql 应用程序之间可能有所不同。

    另一种可能性是 SQL Server 正在为您的 Linq2Sql 查询使用旧的缓存计划。计划可以在每个用户的基础上进行缓存,因此如果您以不同的用户身份运行查询分析器,则可以解释不同的计划。通常您可以将Option (RECOMPILE) 添加到应用程序查询中,但我想这对于Linq2Sql 来说很难。您可以使用DBCC FREEPROCCACHE 清除整个缓存,看看是否加快了 Linq2Sql 查询。

    【讨论】:

    • 我运行 sp_updatestats 大约需要 7 分钟。然后我运行了 DBCC FREEPROCCACHE,它立即返回,没有错误。虽然仍然是相同的行为。您提供的 SELECT 现在显示所有统计数据的今天日期(其中一些是 2 年前的!)。我可能不得不尝试使用存储过程。明天我会尝试比较 SET 选项。谢谢!
    • 顺便说一句。即使在 LINQ 中,如果日期在过去 48 小时内似乎也没问题(不确定这是哪个查询计划,但可能有足够少的行可以进行扫描)。一旦我超过大约 60 小时,它就会切换到另一个查询计划并且永远不会返回。但从查询分析器我可以做一个月、一年、2 年,它会立即返回(这是 233000 行的计数)!再次从探查器中获取相同的确切 SQL。奇怪...
    • 如果您的第一个 LINQ 查询是在 48 小时内,SQL Server 可能会生成一个针对这种情况进行优化的计划。如果您dbcc freeproccache 并且第一次查询超过 60 小时会发生什么?还可以考虑使用 ExecuteQuery (msdn.microsoft.com/en-us/library/bb399403.aspx) 重写 Linq2Sql,它允许您指定 option (recompile)
    • 还是被难住了!我在服务器上打开了 LINQPad 并运行了一个从 1 天到 60 天迭代的查询,它设法在 5 秒内为 60 个查询返回了这个查询。 LINQPad 再次生成与我看到的 ASP.NET 应用程序生成的完全相同的 SQL——它只是使用了一个好的查询计划。我什至重新启动服务器并(最终)升级到 sql server 2008 - 仍然没有做我想要的。如果必须,我可以切换到原始 SQL - 我只是想不明白发生了什么。到目前为止,我非常幸运 LINQ to SQL 对我来说表现良好,查询要复杂得多
    • @Simon:你是否使用完全相同的连接字符串进行连接?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2020-10-13
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多