更新表需要很长时间

时间:2011-01-08 16:31:45

标签: sql sql-server-2008

我在SQL Server 2008(SP2)中有一个表,包含3000万行,表大小为150GB,有几个int列和两个nvarchar(max)列:一列包含文本(1-30000个字符)和一个包含xml(最多100000个字符)。

表没有任何主键或索引(它是临时表)。所以我正在运行查询:

UPDATE [dbo].[stage_table] 
SET [column2] = SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1);

查询运行了3个小时(并且仍未完成),我认为这个时间太长了。是吗?我可以看到.mdf文件的读取速率为5MB / s,写入速率为10MB / s。

如何找出查询运行这么久的原因? “服务器”是RAID7上的i7,24GB RAM,SATA磁盘。

更新:

表包含一个int列,两个nvarchar(20)列和两个nvarchar(max)列。上面的update子句中的Column1和Columns2是nvarchar(20)列。 “大”列未更新。

非常感谢!

6 个答案:

答案 0 :(得分:3)

老实说,这是你正在做的大量工作(文本搜索和替换150千兆字节)。如果分阶段数据来自数据库之外,您可以考虑在那里进行文本操作,而不会产生任何数据库开销。

答案 1 :(得分:1)

你正在对一个字段进行一些字符串操作 - 这是一个非常糟糕的SQL。考虑编写一个SQL CLR函数来执行您需要的操作,而不是使用SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1)

答案 2 :(得分:1)

测试某些东西是否与众不同的一种实用方法是仅更新一些数据。编写一个视图,选择说出前10,000行,并对视图运行更新。

如果对您的服务器预期“正常”的10,000次更新,那么就会发现它只是“要更新的大量数据”。

如果这些小的更新似乎过长,那么请进行更多调查。

至少这为你提供了一个不错的试验场。

答案 3 :(得分:1)

这里有一些选择。但是,在执行此更新后,如果没有关于您打算如何处理数据的更多信息,Larry Lustig的回答听起来是最合适的。但其他选择如下:

  • 将column2创建为计算列而不是物理列。
  • 从登台表中提取数据时执行计算(如果您使用上一个项目符号,也会发生这种情况。
  • 索引column2然后以10,000个记录的块为单位执行更新,其中column2为null。这将使隐含的交易规模保持不变,这可能是目前正在扼杀您的业绩

答案 4 :(得分:1)

我还没有在SQL Server中进行过这种处理,所以我不确定这些建议是否完全适用。但我有足够的信心建议你尝试一下。

我在Oracle中通常做的是在处理所描述的情况(例如单个用户,批处理事件)时处理所有行时完全避免更新。

我将逻辑从update语句迁移回插入行的语句。或者,如果这不可能,我创建一个新表并将更新逻辑放在选择列表中。例如,而不是做

UPDATE [dbo].[stage_table] 
SET [column2] = SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1);

我愿意:

create table stage_table2 as
   select column1
         ,substring(column1, 1, charindex('.', column1)-1) as column2
         ,column3
         ,column4
     from stage_table;

drop table stage_table;

alter table stage_table2 rename to stage_table;
-- re-create indexes and constraints, optionally gather statistics

我也可以使用并行查询和nologging选项来生成非常少的重做并且根本没有撤消,这将胜过具有如此大边际的更新语句甚至不好笑:)当然这是因为Oracle内部,但我认为也可以用SQL Server复制它。 您的描述中有些内容可能会使这种方法效率降低。您有一些非常大的文本列,您必须在CTAS语句中“拖动”。

此外,您需要调查您的硬件设置,因为它不适合处理您抛出的数据量。要么配置有问题,要么你还有很多其他活动:

  

我可以看到有不断阅读   速率为5MB / s,写入速率为10MB / s   到.mdf文件。

我可以在我的女朋友2岁的笔记本电脑上击败它。如果读取速度为5 mb / s,表格为150 GB,则只需要花费8.5小时就能扫描一次。这假设数据库增加了0%的开销,的情况。

答案 5 :(得分:0)

测试某些东西是否与众不同的一种实用方法是仅更新一些数据。编写一个视图,选择说出前10,000行,并对视图运行更新。

如果10,000行更新了您希望服务器“正常”的内容,那么就会发现它只是“要更新的大量数据”。

如果这个小小的更新看起来过长,那么请进行更多调查。

至少这为你提供了一个不错的试验场。