生成SQL查询计划需要5分钟,查询本身以毫秒为单位运行。什么';什么事?

生成SQL查询计划需要5分钟,查询本身以毫秒为单位运行。什么';什么事?,sql,sql-server,tsql,sql-server-2008,stored-procedures,Sql,Sql Server,Tsql,Sql Server 2008,Stored Procedures,我有一个在SQLServer2008上运行的相当复杂(或丑陋,取决于您的看法)的存储过程。它基于一个具有pk表和fk表的视图来进行大量的逻辑。fk表与pk表的左连接次数略多于30次(fk表的设计很差-它使用名称-值对,我需要将其展平。不幸的是,它是第三方,我无法更改) 无论如何,它已经运行了好几个星期了,直到我周期性地注意到运行需要3-5分钟。事实证明,这就是生成查询计划所需的时间。一旦查询计划存在并被缓存,存储过程本身就会非常高效地运行。在有理由重新生成和缓存查询计划之前,一切都会顺利进行 有

我有一个在SQLServer2008上运行的相当复杂(或丑陋,取决于您的看法)的存储过程。它基于一个具有pk表和fk表的视图来进行大量的逻辑。fk表与pk表的左连接次数略多于30次(fk表的设计很差-它使用名称-值对,我需要将其展平。不幸的是,它是第三方,我无法更改)

无论如何,它已经运行了好几个星期了,直到我周期性地注意到运行需要3-5分钟。事实证明,这就是生成查询计划所需的时间。一旦查询计划存在并被缓存,存储过程本身就会非常高效地运行。在有理由重新生成和缓存查询计划之前,一切都会顺利进行


有人见过这个吗?为什么制定计划需要这么长时间?有没有办法让它更快地制定计划

您可以尝试使用一个。计划生成仍将持续一段时间,但应该会大大缩短。

您是否考虑过像这样将您的30加入选择重新写入smth

SELECT [key], NULL AS [a], NULL AS [b]
  INTO #temp
  FROM [pk-table]

UPDATE t SET t.[a] = fk.[a], t.[b] = fk.[b]
  FROM #temp t
  INNER JOIN (
    SELECT f.[key],
      MAX(CASE WHEN f.[name] = 'a' THEN f.[value] ELSE NULL END) AS [a],
      MAX(CASE WHEN f.[name] = 'b' THEN f.[value] ELSE NULL END) AS [b]
    FROM [fk-table] f
    GROUP BY f.[key]
    ) fk ON (fk.[key] = t.[key]

虽然这可能不是您最初问题的答案:)

但某些因素会导致计划需要重新编译,例如统计数据更新或DDL更改。 列表如下所示:

当前形式的查询总是需要3-5分钟才能重新编译:这是不可避免的

假设您无法更改它(透视、使用触发器维护“正确”的表等),那么您只能控制重新编译的发生时间


雷姆斯的计划指南答案是一种方式。我还会查看我的统计维护,并确保它是在一夜之间完成的,比如说,所以它只在一天开始时发生一次

谢谢。我尽量避免使用计划指南,除非我真的不得不这样做。一夜之间强制统计是一个很好的解决方案。此外,我们还考虑过尝试使用触发器。我们还不清楚桌子上的实际负载,因为它还不是一个带电系统。但我想试试。这也值得一试。虽然我尝试过PIVOT和一些CTE,但到目前为止,作为视图的左侧连接是最有效的。你以前见过这样更快吗?见过。我有相同的逻辑(多个(大约20个)“fk表”左连接到一个“主表”),在添加同一个表的另一个连接后,执行时间显著增加。重新编写巨大的一步选择到两步选择更新真的很有帮助。但也许这只是不幸指数的一个特殊情况,我没有去挖掘。(很抱歉,您的帖子中遗漏了“on a view”语句)np-视图只是简化了查询的重用,我不确定这是否必要。为什么生成计划需要这么长时间?部分是在查询优化过程中考虑的组合数。一个30个连接选择有30个!(30阶乘)考虑不同的接合顺序,或约2.65 e32。而订单只是查询优化的一个方面来考虑。按照Rad的建议,将查询分解成更小的部分,将子结果存储在临时表中,可以大大减少优化工作,但可能会给出更慢的计划。通过删除连接并在查询的select子句中进行选择,我可以将执行计划时间缩短到3秒。