一般的なデータベース/SQLサーバーの設計について質問があります。
24時間365日アクセスされている300万行のテーブルがあります。テーブル内のすべてのレコードを更新する必要があります。テーブルを更新するときにユーザーへの影響を最小限に抑えるために、これを行うためのいくつかの方法を教えてください。
前もって感謝します。
一般的なデータベース/SQLサーバーの設計について質問があります。
24時間365日アクセスされている300万行のテーブルがあります。テーブル内のすべてのレコードを更新する必要があります。テーブルを更新するときにユーザーへの影響を最小限に抑えるために、これを行うためのいくつかの方法を教えてください。
前もって感謝します。
通常、行を更新するための単一の更新ステートメントを記述します。しかし、あなたの場合、あなたは実際にそれを分割したいと思います。
http://www.sqlfiddle.com/#!3/c9c75/6 は、一般的なパターンの実用的な例です。バッチサイズを2にする必要はなく、100,000または25,000が必要な場合もあります。システムでテストして、迅速な完了と低ブロッキングの最適なバランスを決定する必要があります。
declare @min int, @max int
select @min = min(user_id), @max = max(user_id)
from users
declare @tmp int
set @tmp = @min
declare @batchSize int
set @batchSize = 2
while @tmp <= @max
begin
print 'from ' + Cast(@tmp as varchar(10)) + ' to ' + cast(@tmp + @batchSize as varchar(10)) + ' starting (' + CONVERT(nvarchar(30), GETDATE(), 120) + ')'
update users
set name = name + '_foo'
where user_id >= @tmp and user_id < @tmp + @batchsize and user_id <= @max
set @tmp = @tmp + @batchSize
print 'Done (' + CONVERT(nvarchar(30), GETDATE(), 120) + ')'
WAITFOR DELAY '000:00:001'
end
update users
set name = name + '_foo'
where user_id > @max
このようなパターンを使用して、テーブルサイズの約10倍のユーザーテーブルを更新します。100,000チャンクの場合、約1時間かかります。もちろん、パフォーマンスはハードウェアによって異なります。
ユーザーへの影響を最小限に抑えるために、一度に特定の数のレコードのみを更新します。更新する数は、私の意見では他の何よりもハードウェアに依存しています。
すべてのものデータベースと同様に、それは異なります。負荷パターンは何ですか(つまり、ユーザーは主にテーブルの最後から読んでいますか)?新しいレコードが追加された場合、どのように追加されますか?インデックスフィルファクターの設定と実際の値は何ですか?更新により、インデックスの再計算が強制されますか?ロックを減らすためにアップデートを分割できますか?もしそうなら、障害が発生した場合の堅牢なロールバック機能が必要ですか?すべての行に同じ値を設定していますか、それとも行ごとの計算が必要ですか、それとも一致する行ごとのソースがありますか?
ループまたはカーソルを使用して、一度に1行ずつテーブルを調べます。各更新で行ロックが使用されていることを確認してください。
まだ更新する必要のある行を識別する方法がない場合は、最初に別のテーブルを作成して主キーと更新インジケーターを保持し、そこにすべての主キー値をコピーしてから、どこまで進んでいるかを追跡しますそのテーブル。
これも最も遅い方法になります。少し速くする必要がある場合は、行ロックのヒントを使用して、一度に数千行を更新します。