2012-03-02 6 views
0

Updateステートメントでは、最近更新プログラムが3分かかるため、更新に2時間ほどかかります。最近のdbデザインでは、以下のようにストアドプロシージャコードを変更しました。行数が10万を超えるテーブルのVarchar列の更新

詳細は私のシナリオです:私は10百万行以上の非常に大きなファクトテーブルを持っており、条件が満たされたときにそのファクトテーブルの列を更新する必要があります。だから我々は、その列を更新するUPDATE文を書いた:2時間のクエリを実行するために作っているの文が原因でSET文である私の理解あたりとして

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

Update 
    fopty 
set 
    Metrickey = metrickey+','[email protected] 
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' 

は、上記のクエリを最適化する方法は、あります

Metrickey = Metrickey + @var 

ここMetrickey列がvarchar@var変数であり、それはより多くの時間を取っているこの文字列を連結するために、もvarchar(max)です。

上記のクエリを最適化することができたら、大きな助けになるので、varchar列をvarcharという値で更新するための最良の方法を提案してください。

+2

'metrickey'の実際のデータタイプは' max'ですか、定義された長さですか?この問題の一部は、変数に 'max'データ型を使用することです。 – JNK

+2

WHERE句のフィールドにインデックスがありますか?フィールドはどのように結合されますか?各テーブルのおおよその行数はどのくらいですか?クエリプランには何が表示されますか(つまり、どのステップのコストが最も高いか)。 –

+2

@JNKと合意しましたが、データ型が最大データ型であっても追加したいと思っていましたが、本当に必要ですか? – HLGEM

答えて

0

VARCHAR列を更新するための本当の秘密超高速ソリューションはありません。何があっても比較的遅くなるでしょうが、痛みを和らげるためにできることがあります。

すべてのテーブルに適切なカバーされたインデックスがあることを確認してください。

注:あなたのコードに誤植があると仮定します - "Update fopty"​​は "Update opty"​​を正しく読みますか?

optyfactテーブル(optyエイリアス)の場合、optyidおよびatukeyカラムには、metrickeyを含むインデックスが必要です。

他のテーブルの場合は、すべての列をインデックスに入れます。他の列を含めても構いません。

すべての設定が完了したら、クエリアナライザを使用して、すべてのテーブルでINDEX SEEKを実行していることを確認します。そうでない場合は、指示どおりに長時間実行されます。

これを超えると、狭い列に参加していることを確認してください。 INTは良いですが、VARCHARは悪いです。

最後に、metrickey列がクラスタ化インデックスの一部でないこと、または更新中にテーブル自体が再編成を継続することを確認してください。

これだけです。がんばろう!

0

ワンショット内のすべての行を更新するのではなく、バッチ単位で(一度に100,000行ずつ)更新することを検討する必要があります。必ずしも全体的に時間がかかるとは限りませんが、2時間すべてをロックしません。実際の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; 
関連する問題