代码之家  ›  专栏  ›  技术社区  ›  Erik Funkenbusch

为什么查询超时?第2版

  •  1
  • Erik Funkenbusch  · 技术社区  · 14 年前

    This Question

    解决方案是,清除执行计划缓存在当时似乎是可行的,但我一次又一次地遇到同样的问题,清除缓存似乎不再有帮助。这里一定有更深层次的问题。

    Linq查询和执行的SQL之间有什么区别?

    我有一个短期的解决方法,那就是不使用.Distinct()作为列表返回集合,然后在列表上使用.Distinct,这大约需要2秒钟。但是,我不喜欢在web服务器上执行SQL Server工作。

    更新:

    当通过Linq执行代码时,sql事件探查器会显示此代码,这与查询基本相同。

    sp_executesql N'SELECT DISTINCT [t5].[AccountGroupID], [t5].[AccountGroup] 
        AS [AccountGroup1]
    FROM [dbo].[TransmittalDetail] AS [t0]
    INNER JOIN [dbo].[TransmittalHeader] AS [t1] ON [t1].[TransmittalHeaderID] = 
        [t0].[TransmittalHeaderID]
    INNER JOIN [dbo].[LineItem] AS [t2] ON [t2].[LineItemID] = [t0].[LineItemID]
    LEFT OUTER JOIN [dbo].[AccountType] AS [t3] ON [t3].[AccountTypeID] = 
        [t2].[AccountTypeID]
    LEFT OUTER JOIN [dbo].[AccountCategory] AS [t4] ON [t4].[AccountCategoryID] = 
        [t3].[AccountCategoryID]
    LEFT OUTER JOIN [dbo].[AccountGroup] AS [t5] ON [t5].[AccountGroupID] = 
        [t4].[AccountGroupID]
    LEFT OUTER JOIN [dbo].[AccountSummary] AS [t6] ON [t6].[AccountSummaryID] = 
        [t5].[AccountSummaryID]
    WHERE ([t1].[TransmittalEntityID] = @p0) AND ([t1].[DateRangeBeginTimeID] = @p1) AND 
    ([t1].[ScenarioID] = @p2) AND ([t6].[AccountSummaryID] = @p3)',N'@p0 int,@p1 int,
       @p2 int,@p3 int',@p0=196,@p1=20100101,@p2=2,@p3=0
    

    查询之间的唯一区别是Linq使用sp挈u executesql执行它,而SSMS不执行它,否则查询是相同的。

    更新:

    我尝试过各种事务隔离级别,但都无济于事。我还将ARITHABORT设置为在执行时强制重新编译,没有区别。

    5 回复  |  直到 4 年前
        1
  •  1
  •   KristoferA    14 年前

    糟糕的计划很可能是参数嗅探的结果: http://blogs.msdn.com/b/queryoptteam/archive/2006/03/31/565991.aspx

    不幸的是,没有什么好的通用方法(据我所知)来避免L2S的这种情况。 context.ExecuteCommand命令 (“sp\u recompile…”)将是一个丑陋的,但可能的解决办法,如果查询不经常执行。

    稍微改变查询以强制重新编译可能是另一种情况。

    将查询的部分(或全部)移动到视图*、函数*或存储过程*数据库端将是另一种解决方法。
    * = 您可以使用本地参数(func/proc)或优化器提示(全部三个)来强制执行“好”计划

    顺便问一下,您是否尝试过更新相关表格的统计数据?SQL Server的自动更新统计信息并不总是能完成这项工作,因此,除非您有计划的工作要做,否则可能值得考虑编写脚本和计划更新统计信息。。。根据需要上下调整样本大小也会有所帮助。

    有一些方法可以通过在所涉及的表上添加*(或删除*)正确的索引来解决这个问题,但是在不知道底层数据库模式、表大小、数据分布等的情况下,很难给出更具体的建议。。。
    * = 缺少和/或重叠/冗余索引都可能导致糟糕的执行计划。

        2
  •  1
  •   RyanHennig    14 年前

    Linqpad提供给您的SQL可能并不完全是发送到DB的SQL。

    以下是我的建议:

    1. 将整个statment粘贴到SSMS中,并启用“Show Actual Execution Plan”选项。
    2. 在这里张贴最终的计划,供人们解剖。

    需要寻找的关键事项:

    • 图形平面中的宽箭头,指示正在处理的大量中间行。

    如果您使用的是SQL2008,查看计划通常会告诉您是否缺少索引,应该添加索引以加快查询速度。

    另外,您是否正在对其他用户加载的数据库执行操作?

        3
  •  1
  •   Jim L    14 年前

    乍一看,有很多连接,但我只能看到一件事,即在我面前有一个模式的情况下,立即减少数量…看起来你不需要AccountSummary。

    [t6].[AccountSummaryID] = @p3
    

    [t5].[AccountSummaryID] = @p3
    

        4
  •  1
  •   RyanHennig    14 年前

        5
  •  0
  •   EchoCoder    14 年前

    检查SSMS会话和应用程序之间是否具有相同的事务隔离级别。这是我所见过的相同查询之间的巨大性能差异的最大罪魁祸首。

    另一方面,如果您是手工制作SQL,您可以尝试将条件从WHERE子句移到适当的JOIN子句中。这实际上改变了SQLServer执行查询的方式,并可以生成更有效的执行计划。我见过这样的情况:将筛选器从where子句移到JOINs中会导致sqlserver在执行计划的早期对表进行筛选,并显著地改变了执行时间。