0

大規模なデータベースを使用していますが、選択/更新を最適化する方法についてアドバイスが必要です。これが例です:

create table Book (
   BookID int,
   Description  nvarchar(max)
)
-- 8 million rows

create table #BookUpdates (
   BookID int,
   Description  nvarchar(max)
)
-- 2 million rows

800万冊の本があり、そのうち200万冊のジャンルを更新する必要があると仮定します。

問題:これらの更新を実行する時間は非常に長いです。これにより、データベースからステートメントを実行しようとしているユーザーがブロックされることがあります。私は解決策を考え出しましたが、そこにもっと良いものがあるかどうか知りたいです。私はこのような1回限りのランダムな更新をたくさん準備する必要があります(何らかの理由で)

-- normal update
update b set b.Description = bu.Description
from Book b
join #BookUpdates bu
   on bu.BookID = b.BookID

-- batch update
while (@BookID < @MaxBookID)
begin
   update b set b.Description = bu.Description
   from Book b
   join #BookUpdates bu
      on bu.BookID = b.BookID
   where bu.BookID >= @BookID
      and bu.BookID < @BookID + 5000

   set @BookID = @BookID + 5000
end

2番目の更新ははるかに高速に動作します。このソリューションが気に入っているのは、ステータスの更新を残りの期間について自分自身に印刷でき、お客様のパフォーマンスの問題を引き起こさないためです。

質問:ここで重要な何かが欠けていますか?一時テーブルのインデックス?

正規化コメントが増えないように、EXAMPLEテーブルを更新しました。本ごとに1つの説明のみ:)

4

2 に答える 2

2

NOLOCKSQLクエリでまたはREADUNCOMITTEDヒントを使用することにより、クエリ側でのブロックを防ぐことができます。

パフォーマンスの本当の問題は、おそらくログへの変更の蓄積です。5,000のグループで変更をバッチ処理する方法は非常に合理的です。バッチテーブルで更新を設定しているため、テーブルでバッチ番号を計算し、それに基づいてループを実行することもできます。

于 2013-02-03T15:55:55.670 に答える
0

更新を実行する前に、まず独自の提案を試し、一時テーブルにインデックスを付けます。

CREATE INDEX IDX_BookID ON #BookUpdates(BookID)

インデックスありとインデックスなしで試して、ランタイムへの影響を確認してください。このテストでユーザーに影響を与えないようにする場合は、(可能であれば)勤務時間外に実行するか、最初にBookを別の一時テーブルにコピーしてテストします。

とにかく、ボリュームを考えると、他のプロセスのブロックが発生することを期待しています。このテーブルに対して他のプロセスが実行されていないときに更新をスケジュールできない場合(これは理想的なソリューションです)、既存のバッチ更新は完全に有効なソリューションのように見えます。一時テーブルにインデックスを付けると、それも役立つ可能性が高いため、ブロッキングを発生させずにバッチサイズを増やすことができる場合があります。

于 2013-02-03T16:01:13.343 に答える