SQL Server查询占用100%的CPU并运行数小时

时间:2009-05-05 06:42:29

标签: sql-server performance

我的查询现在每天运行2年多一点,通常需要不到30秒的时间才能完成。突然间,昨天,查询开始需要3个多小时才能完成,并且整个时间都在使用100%的CPU。

SQL是:

SELECT
  @id, 
  alpha.A, alpha.B, alpha.C, 
  beta.X,  beta.Y,  beta.Z, 
  alpha.P, alpha.Q
FROM 
  [DifferentDatabase].dbo.fnGetStuff(@id) beta 
  INNER JOIN vwSomeData alpha ON beta.id = alpha.id

alpha.id是BIGINT类型,beta.id是INT类型。 dbo.fnGetStuff()是一个简单的SELECT语句,使用WHERE id = @id在同一个数据库中的表上有2个INNER JOIN。该函数返回大约11000个结果。

视图vwSomeData是一个简单的SELECT语句,带有两个INNER JOIN,返回大约590000个结果。

视图和函数在自己执行时都会在不到10秒的时间内完成。首先将函数的结果选择到临时表中,然后加入该函数,使得查询在< 10秒

如何解决正在发生的事情?我没有在活动管理器中看到任何锁定。

8 个答案:

答案 0 :(得分:4)

查看查询计划。我的猜测是执行计划中有一个或更多的表扫描。这将导致您在结果中获得的少量记录的大量I / O.

答案 1 :(得分:2)

您可以使用SQL Server Profiler工具监视SQL Server上运行的查询。它没有显示锁定,但它也可以为您提供有关如何通过建议索引来改进查询的提示。

答案 2 :(得分:1)

如果您有一个合理的SQL Server Management Studio版本,它也有一个数据库调优顾问,在工具下。它需要从Profiler中获取一些内容,并提出一些有时非常有用的建议。确保没有太多查询 - 建立建议需要很长时间。

我不是这方面的专家,但过去运气不错。

答案 3 :(得分:1)

您需要使用功能吗?您可以将整个事物重写到存储过程中,在该过程中将@ID作为参数传递。

即使您的表有索引,因为您将@ID作为变量传递给WHERE子句可能会大大增加查询运行的时间。

不能使用索引的原因是查询分析器在选择执行查询的访问方法时不知道变量的值。因为这是一个批处理文件,所以只有一个Transact-SQL代码传递,阻止查询优化器知道它需要知道什么才能选择使用索引的访问方法。

如果无法重写SQL,可能需要考虑INDEX查询提示。

也许有可能,因为这刚刚开始发生,INDEX已经变得支离破碎,可能需要重建。

答案 4 :(得分:0)

我在加入返回大型数据集的函数方面遇到了类似的问题。我必须做你已经建议的事情。将结果放在临时表中并加入。

答案 5 :(得分:0)

看看估计的计划,这可能会有所启发。通常,当查询成本变得更加昂贵时,这是因为正在使用循环或合并连接,其中散列连接更合适。如果在估计的计划中看到循环或合并连接,请查看它预期要处理的行数 - 它是否远小于您知道实际将在其中运行的行数?您还可以指定提示以使用散列连接,并查看它是否执行得更好。如果是这样,请尝试更新统计信息,看看它是否在没有提示的情况下返回到散列连接。

SELECT
  @id, 
  alpha.A, alpha.B, alpha.C, 
  beta.X,  beta.Y,  beta.Z, 
  alpha.P, alpha.Q
FROM 
  [DifferentDatabase].dbo.fnGetStuff(@id) beta 
  INNER HASH JOIN vwSomeData alpha ON beta.id = alpha.id

答案 6 :(得分:0)

- 不知道什么类型的架构到位,只是试图抛出想法:

像其他人一样说...使用Profiler并找到痛苦的根源......但我认为这是其他数据库的功能。由于该函数可能是痛苦的根源,您是否考虑过[DifferentDatabase]上的一些非规范化或任何内容。我认为你会发现在使用索引而不是昂贵的函数加入更扁平的表时会有更多的可扩展性。

答案 7 :(得分:0)

运行此命令:

SET SHOWPLAN_ALL ON

然后运行您的查询。它将显示执行计划,在索引或表上查找“SCAN”。这很可能是您现在的查询正在发生的事情。如果是这种情况,请尝试找出它现在没有使用索引的原因(刷新统计数据等)