100mmレコードでJOINを使用して更新します。これをより適切に行う方法は?(T-SQL)


11

実際には、1つのテーブルの1億レコードを更新する必要があります。つまり、列のvarchar値を単にIDに置き換えることでテーブルを正規化します。(「置換」と言いますが、実際にはIDを別の列に書き込んでいます。)

私が達成しようとしているのは、データセットを正規化することです。まだ正規化されていないデータにはインデックスがありません。私の考えは、更新が完了した後、varchar値をtinyint値で置き換える外部キーにインデックスを付けるのを待つ代わりに、生の値にインデックスを構築しないことでした。

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

バックグラウンド

  • サーバー2008 R2でMSSQL 2008 R2を使用
  • サーバーには8 GBのRAMがあります
  • サーバーには1つのRAID10、7200 RPM SATAがあります(すばらしいですが、本番環境ではこれはデータの読み取りのみを行い、データの書き込みは行いません。さらに、最近のHDの不足により、コストのためにこれが必要になりました)。
  • サーバーにはデュアルクアッドコアXeon CPUが搭載されています
  • マシンは他に何もしていません(現在は開発専用で、このプロセスのみ)
  • 単純なロギングがオン(?-しかし、ロールバックできるようにログを記録しますか?)
  • クエリは2つの異なるDBを参照することに注意してください。
  • 更新されるテーブルのレコードの「幅」は455バイトです

実行中のリソース

  • 物理RAMがいっぱいです
  • ディスクI / Oが最大になりました
  • CPUはほとんど何もしていません(チョークポイントはI / Oです)
  • 実行時間は14時間で、カウントされています!

正規化の更新後に列(AutoClassName)を削除する場合でも、生データのインデックスが必要になるなど、いくつかのことが疑われます。また、JOINを開始するときにばかげて見えたJOINではなく、一度に1レコードずつテーブルをループダウンする必要があるのか​​どうかも疑問に思っていましたが、今はもっと高速だったようです。

残りの正規化更新(これと同様)の方法をより迅速に変更するにはどうすればよいですか?

回答:


7

これを単一の(非常に大きな)トランザクションとして実行しようとしています。代わりに、更新を小さいバッチで実行します。

また、次のメリットもあります。

  • AutoData.dbo.AutoClass.AutoClassNameの一時インデックス
  • より多くのRAM。より多くのRAM。

1
+1 TOP条項を使用したバッチ更新に同意します。それが私のアプローチです。
トーマス・ストリンガー、2012

UPDATE TOPを実行する場合、WHERE句が必要になります(WHERE AutoClassIDはNULL)?WHERE句は新しいパフォーマンスヒット(私が現在行っていないテーブルスキャン)を導入しませんか?JOINで発生するRAMの問題が軽減されることは間違いありません。
Chris Adragna

私の応答は長い間遅れていますが、私の場合、SET ROWCOUNTが最も効果的であることがわかりました。
Chris Adragna 2013

10

私は別のアプローチを取るでしょう。

既存のテーブルを更新する代わりに、必要なものを含む新しいテーブルを作成するだけです。

これはほぼ確実に速くなります:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

現在書かれているように、多くの論理演算が行われています:

  • A.AutoClassNameのすべての値を読み取る
  • B.AutoClassNameのすべての値を読み取る
  • AとBの値を比較する
  • 一致するセットのうち、B.AutoClassIDのすべての値を読み取ります
  • 存在するインデックスを介して、A.AutoClassIdの既存の値をB.AutoClassId値に更新します。

これは、特に私が抱えているディスクI / Oの問題を考えると、素晴らしく単純なアプローチのように聞こえます。迅速に回答していただきありがとうございます。
Chris Adragna

1
ログファイルとデータファイルに十分な空き領域があることを再確認することをお勧めします。ファイルが自動拡大している場合、パフォーマンスは急激に低下します。多くの場合、大きな一回限りの更新を実行していて、ログファイルを認識せずに自動拡張している人を見かけます。
ダリン海峡

5

一度に1行ずつテーブルをループすると、速くなりません。

疑いがあり、あなたが確認したとおり、これはI / Oバウンドになります。1つのディスクを使用すると、読み取り、書き込み、トランザクションログ、および(任意の)一時作業スペースがすべて同じI / Oで競合します。

単純な回復でもトランザクションは記録されますが、ログはチェックポイントによってクリアされます。初期ログサイズと自動拡張設定により、I / Oの速度が低下している可能性があります。トランザクションログは、変更に対応するために拡張する必要があります。

AutoClassNameフィールドのインデックスを作成しましたか?AutoClass値はいくつありますか?

I / Oの制限に基づいて、更新をバッチ処理する必要がある場合があります。したがって、100万を更新し、チェックポイントを繰り返します。


AutoClass値は15しかありません。あなたのコメントは私の疑念の多くを確認します(そして苦痛!)。答えてくれてありがとう。
Chris Adragna

3

結合フィールドのインデックスを作成します。

終了したらいつでもインデックスを削除できます。

インデックスが更新のパフォーマンスを大幅に改善しなかったとしたら、私は非常に驚きます。


インデックスは確実に改善するでしょう。問題は、インデックスの作成にかかる時間(1回の使用のみ)よりも向上するかどうかです。おそらくそうだ。:)
Chris Adragna

3

希望どおりにエクスポートし、新しいテーブルを作成してインポートします。ボーナスとして、奇跡が起こった場合に備えて、バックアップとしてデータのコピーを作成できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.