web-dev-qa-db-ja.com

ダウンタイムを最小限に抑えながら、大きな(700M行)ホット(1秒あたり複数のトランザクション)テーブルから列を削除するにはどうすればよいですか?

私の研究によると、それはメタデータの変更にすぎないので、(排他ロックを取得した場合)すぐに列をテーブルにドロップできます。

テーブルには、常にレコードを挿入および更新する2つの異なるサービスがあります。すごく暑い。このレベルの活動の完全な再現環境を開発せずに、どうすれば

ALTER TABLE x DROP COLUMN y 

排他ロックの取得に成功し、すばやくドロップしてから、テーブルのロックを解除しますか?

SQL Serverはこの要求をどのようにキューに入れますか(たとえば、先入れ先出し)? DROP COLUMNが本当にほんの数分しかかからないと確信できますか?

このテーブルをPRODで長時間ロックすることは受け入れられないため、驚きを避けようとしています。

その他の注意事項:後でオンラインでインデックスを再作成して、インデックスを最適化し、スペースを再利用します。

3
Cyndi Baker

SQL Serverはこの要求をどのようにキューに入れますか(たとえば、先入れ先出し)? DROP COLUMNが本当にほんの数分しかかからないと確信できますか?

ALTER TABLEのロックのしくみは、ALTERを実行するためにスキーマ変更ロック(Sch-M)が必要なことです。テーブルにアクセスする他のすべてのクエリには、スキーマ安定性ロック(Sch-S)が必要です。 Sch-MとSch-Sには互換性がありません。

また、Sch-Mロックの取得を待機している間、Sch-Sロックに対するnew要求をブロックします。したがって、すべての処理中のクエリとトランザクションがテーブルのSch-Sロックを解放するまで待機し、待機している間、すべての新しいクエリをブロックします。これはDDLロックの正常な動作方法であり、テーブルで長時間実行されるクエリがない限り、正常に動作します。

ただし、DDLが滞る可能性があるクエリを長時間実行している場合、DDLはすべての新しいクエリをブロックします。そのため、短時間実行と長時間実行の両方の操作があるビジーなシステムでDDLを実行することは問題でした。

優先度の低い待機は、DDLステートメントが新しいクエリをブロックせずに優先度を下げて待機できるようにすることで、この問題を解決します。 DDLセッションは、他のセッションがテーブルにロックを設定していない「ウィンドウ」を待つだけで実行されます。ただし、DDLセッションは新しいクエリをブロックしないため、永久に待機する可能性があります。

残念ながら、優先度の低い待機は列の削除に対して有効になっていません。フィードバック項目を作成して、実装するように依頼できます here 。オンラインでのインデックスの再構築とパーティション切り替えが有効になっています。

mostlyLOCK_TIMEOUTおよび再試行でこの動作をエミュレートできます。したがって、ロックタイムアウトを使用してDDLセッションを構成し、ロックをすばやく取得できない場合は、ALTER TABLEを破棄します。

したがって、次のように変更を実行します。

set lock_timeout 1000 --1 second
alter table SomeTable
drop column if exists ColumnToDrop 

そして、それはすぐに成功するか、ロックタイムアウトエラーで失敗します。これを無人ジョブで実行する場合は、再試行ループを使用して、ALTER TABLEがすぐに成功するまで試行を続けることができます。

このようなもの:

set lock_timeout 1000 --1 second
declare @tries int = 0

while 1=1
begin 
    begin try
        set @tries = @tries + 1;

        alter table SomeTable
        drop column if exists ColumnToDrop 

        print 'complete'
        break;
    end try
    begin catch
      if @tries > 10 or error_number() <> 1222 throw;

      declare @msg nvarchar(2000) = concat('retry ', @tries);
      print @msg
    end catch
end