按顺序运行时SQL查询会变慢,但单独运行时会很快

时间:2012-01-04 07:21:39

标签: sql sql-server

我有一个表,我将使用昂贵的计算值(使用来自不可变XML列的xquery)填充值。为了加快部署到生产,我在测试服务器上预先计算了值,并使用BCP保存到文件中。

我的脚本如下

-- Lots of other work, including modifying OtherTable

CREATE TABLE FOO (...)
GO

BULK INSERT FOO
FROM 'C:\foo.dat';
GO

-- rerun from here after the break

INSERT INTO FOO 
  (ID, TotalQuantity)
SELECT 
e.ID, 
SUM(e.Quantity) as TotalQuantity
FROM (select 
    o.ID,
    h.n.value('TotalQuantity[1]/.', 'int') as TotalQuantity
FROM dbo.OtherTable o
    CROSS APPLY XmlColumn.nodes('(item/.../salesorder/)') h(n)
WHERE o.ID NOT IN (SELECT DISTINCT ID FROM FOO)
) as E
GROUP BY e.ID

当我在管理工作室中运行脚本时,前两个语句在几秒钟内完成,但最后一个语句需要4个小时才能完成。由于我的foo.dat是计算管理工作室报告OtherTable,因此(0 row(s) affected)没有添加任何行。

如果我在几分钟后取消查询执行并仅选择最后一个查询并单独运行它将在5秒内完成。

值得注意的事实:

  • OtherTable包含200k行,XmlColumn中的数据非常大,总表大小约为3GB
  • FOO表获得1.3M行

什么可能有所不同?
管理工作室已关闭隐式交易。据我所知,每个语句都会在自己的事务中运行。

更新
如果我首先选择并运行脚本直到-- rerun from here after the break,然后选择并运行最后一个查询,它仍然很慢,直到我取消执行并再次尝试。这至少排除了与脚本中的前一代码一起运行“一起”的任何影响,归结为同一查询在第一次执行时速度慢而在第二次运行时快速运行(在所有其他条件相同的情况下运行)。

3 个答案:

答案 0 :(得分:2)

答案 1 :(得分:1)

是否可能与新创建的Foo表中的统计信息完全错误有关?如果SQL Server在首次运行查询时自动更新统计信息,则第二次运行将根据最新统计信息创建其执行计划。

如果您在批量插入(使用STATS_DATE功能)后立即检查统计信息,然后在取消长时间运行的查询后再次检查,该怎么办?即使查询被取消,统计数据是否也会更新?

在这种情况下,批量插入后的Foo上的UPDATE STATISTICS可以提供帮助。

答案 2 :(得分:0)

不确定它为何会有所帮助,但我将最后一个查询重写为left outer join,然后突然执行时间降至15毫秒。

INSERT INTO FOO 
  (ID, TotalQuantity)
SELECT 
e.ID, 
SUM(e.Quantity) as TotalQuantity
FROM (select 
    o.ID,
    h.n.value('TotalQuantity[1]/.', 'int') as TotalQuantity
FROM dbo.OtherTable o
INNER JOIN FOO f ON o.ID = f.ID
    CROSS APPLY o.XmlColumn.nodes('(item/.../salesorder/)') h(n)
WHERE f.ID = null
) as E
GROUP BY e.ID