我在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)列。 “大”列未更新。
非常感谢!
答案 0 :(得分:3)
老实说,这是你正在做的大量工作(文本搜索和替换150千兆字节)。如果分阶段数据来自数据库之外,您可以考虑在那里进行文本操作,而不会产生任何数据库开销。
答案 1 :(得分:1)
你正在对一个字段进行一些字符串操作 - 这是一个非常糟糕的SQL。考虑编写一个SQL CLR函数来执行您需要的操作,而不是使用SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1)
。
答案 2 :(得分:1)
测试某些东西是否与众不同的一种实用方法是仅更新一些数据。编写一个视图,选择说出前10,000行,并对视图运行更新。
如果对您的服务器预期“正常”的10,000次更新,那么就会发现它只是“要更新的大量数据”。
如果这些小的更新似乎过长,那么请进行更多调查。
至少这为你提供了一个不错的试验场。
答案 3 :(得分:1)
这里有一些选择。但是,在执行此更新后,如果没有关于您打算如何处理数据的更多信息,Larry Lustig的回答听起来是最合适的。但其他选择如下:
答案 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行更新了您希望服务器“正常”的内容,那么就会发现它只是“要更新的大量数据”。
如果这个小小的更新看起来过长,那么请进行更多调查。
至少这为你提供了一个不错的试验场。