更新具有>的表的Varchar列1000万行

时间:2012-03-02 18:48:52

标签: sql sql-server-2008

最近我们在Update语句中遇到了严重的性能问题,之前更新过去需要3分钟,现在更新耗时近2小时。对最近的数据库设计我们更改了存储过程代码,如下所示。

这是我的详细情况:我有超过1000万行的非常大的事实表,我需要在满足条件时更新该事实表的列。所以我们写了一个更新语句来更新该列:

declare @var  varchar(max) = (select metrcikey from metricdim where metrciname ='XYZ')

Update 
    fopty
set 
    Metrickey = metrickey+','+@var 
from 
    optyfact opty 
inner join  
    optydim dim on opty.optyid = dim.optyid
inner join 
    geodim geo on geo.atukey = opty.atukey 
inner join 
    agreementdim ag on opty.optyid = ag.optyid 
inner join 
    account acc on acc.optyid = acc.optyid 
where 
    dim.optytype= 'ABC'
    and geo.atukey =145
    and ag.agreementtype ='Sold'
    and acc.accountteamManager  ='XXX'

有没有办法优化上面的查询,根据我的理解,执行查询2小时的语句是由于SET语句

Metrickey = Metrickey + @var

此处Metrickey列为varchar@var变量也为varchar(max),要连接此字符串,需要花费更多时间。

如果可以优化上述查询,对我来说将是一个很好的帮助,因此请建议使用varchar值更新varchar列的最佳方法。

2 个答案:

答案 0 :(得分:0)

没有用于更新VARCHAR列的真正秘密超快解决方案。无论如何,它都会相对缓慢,但你可以采取一些措施来减轻痛苦。

确保所有表格上都有适当的覆盖索引。

注意:我将假设你的代码中有一个拼写错误 - “Update fopty”应该是“Update opty”,对吗?

对于optyfact表(opty别名),您应该在optyidatukey列上包含metrickey的索引。

对于其他表,将所有列放在索引中 - 不要担心包括(覆盖)任何其他列。

完成所有设置之后,请通过查询分析器确保您在所有表格上执行INDEX SEEK,否则这将会运行一段时间,就像您指示的那样。

除此之外,请确保您加入狭窄的列。 INT很好,VARCHAR很糟糕。

最后一件事:确保metrickey列不是您的聚集索引的一部分,或者表将在更新期间继续重新组织。

这就是我得到的全部。祝你好运!

答案 1 :(得分:0)

您应该考虑批量更新(例如,一次更新100,000行),而不是尝试一次更新所有行。它不一定总需要花费更少的时间,但它不会将所有内容锁定两个小时。我们可以将实际的optyid值转储到临时表中,这样我们就不必在更新中连续引用基表了。

CREATE TABLE #q(rn INT IDENTITY(1,1) PRIMARY KEY, optyid INT);

DECLARE 
  @rc    INT, 
  @step  INT = 1,
  @chunk INT = 100000; 

INSERT #q(optyid) SELECT DISTINCT opty.optyid
FROM dbo.optyfact AS opty 
INNER JOIN dbo.optydim AS dim      ON opty.optyid = dim.optyid
INNER JOIN dbo.geodim AS geo       ON geo.atukey = opty.atukey 
INNER JOIN dbo.agreementdim AS ag  ON opty.optyid = ag.optyid 
INNER JOIN dbo.account AS acc      ON acc.optyid = acc.optyid 
WHERE 
  dim.optytype = 'ABC';
  AND geo.atukey = 145
  AND ag.agreementtype = 'Sold'
  AND acc.accountteamManager = 'XXX';

SET @rc = @@ROWCOUNT;

WHILE @step <= ((@rc / @chunk) + 1)
BEGIN
    BEGIN TRANSACTION;

    UPDATE o SET MetricKey += ',' + @var
    FROM dbo.optyfact AS o
    INNER JOIN #q AS q ON o.optyid = q.optyid
    WHERE q.rn BETWEEN (((@step-1)*@chunk)+1) AND (@step*@chunk);

    COMMIT TRANSACTION;
    CHECKPOINT;
    SET @step += 1;
END

DROP TABLE #q;