11

約 400 万件のレコードを持つテーブルからフィールドを変更したいと考えています。これらのフィールドの値がすべて NOT NULL であることを確認し、このフィールドを NOT NULL に変更したい

ALTER TABLE dbo.MyTable
ALTER COLUMN myColumn int NOT NULL

... この更新を行うには永遠にかかるようです。それをスピードアップする方法はありますか、それとも営業時間外に一晩中やっているだけですか?

また、これによりテーブルロックが発生する可能性がありますか?

4

3 に答える 3

4

私が知っているこれを「すばやく」(*)行う唯一の方法は、

  • 必要なレイアウトを持つ「シャドウ」テーブルを作成する
  • ソーステーブルにトリガーを追加して、挿入/更新/削除操作がシャドウテーブルにコピーされるようにします(ポップアップする可能性のあるNULLをキャッチするように注意してください!)
  • すべてのデータをソースからシャドウ テーブルに、場合によっては小さいチャンクでコピーします (トリガーによって既にコピーされたデータを処理できることを確認し、データが新しい構造 (ISNULL(?) ! )
  • 他のテーブルとの間のすべての依存関係をスクリプト化する
  • すべてが完了したら、明示的なトランザクション内で次を実行します。
    • ソーステーブルとシャドーテーブルで排他テーブルロックを取得します
    • スクリプトを実行して依存関係をソーステーブルにドロップします
    • ソーステーブルの名前を別の名前に変更します (例: サフィックス _old)
    • シャドー テーブルの名前をソース テーブルの元の名前に変更する
    • スクリプトを実行して、すべての依存関係を再度作成します

このテーブルを参照するテーブルの量とサイズによってはかなりの時間がかかる可能性があるため、トランザクションの外で最後のステップを実行することをお勧めします。最初のステップはそれほど時間はかかりません。

いつものように、最初にテストサーバーでテストを実行するのがおそらく最善です =)

PS: NOCHECK を使用して FK を再作成しようとしないでください。オプティマイザーがそれらを信頼せず、クエリ プランの作成時に考慮しないため、無駄になります。

(*: すぐに : ダウンタイムを最小限に抑えて)

于 2011-05-23T13:14:49.937 に答える
4

フィールドを変更して、フィールドをチェックせずに null にならないようにすることができます。営業時間外に実行しないことが本当に心配な場合は、フィールドに制約を追加して、代わりに null でないことを確認できます。これにより、チェックなしオプションを使用して、400 万行のそれぞれをチェックして更新するかどうかを確認する必要がなくなります。

CREATE TABLE Test
(
    T0 INT Not NULL,
    T1 INT NUll 
)

INSERT INTO Test VALUES(1, NULL) -- Works!

ALTER TABLE Test
    WITH NOCHECK
        ADD CONSTRAINT N_null_test CHECK (T1 IS NOT NULL)

    ALTER COLUMN T1 int NOT NULL 

INSERT INTO Test VALUES(1, NULL) -- Doesn't work now!

実際には 2 つのオプションがあります (3 つ目のオプションを追加、編集を参照):

  1. 新しい行が更新されないようにし、元の行を変更しないままにする制約を使用します。
  2. null の行を別のものに更新してから、not null 変更オプションを適用します。プロセスがテーブルからロックアウトされることを気にしない限り、これは実際には営業時間外に実行する必要があります。

特定のシナリオに応じて、いずれかのオプションが適している場合があります。ただし、営業時間外に実行する必要があるため、このオプションは選択しません。長い目で見れば、深夜に更新に費やす時間は、数時間節約するために近道をすることで直面する可能性のある頭痛と比較して、十分に費やされるでしょう.

以上のことから、オプション 2 を使用する場合は、勤務時間外の作業量を最小限に抑えることができます。列を変更する前に、行をnull以外に更新する必要があるため、カーソルをゆっくりと書き込むことができます(一度にすべてを行う場合と比較して)

  1. 各行を通過する
  2. null かどうかを確認する
  3. 適宜更新してください。これにはかなり時間がかかりますが、他のプログラムがテーブルにアクセスするのをブロックするテーブル全体をロックすることはありません。( with(rowlock)テーブルのヒントを忘れないでください!)

編集: 3 番目のオプションを考えました。適切な列を含む新しいテーブルを作成し、元のテーブルから新しいテーブルにデータをエクスポートできます。これが完了したら、元のテーブルを削除して、新しいテーブルの名前を古いものに変更できます。これを行うには、元の依存関係を無効にし、完了したら新しい依存関係を元に戻す必要がありますが、このプロセスにより、時間外に行う必要がある作業の量が大幅に削減されます。これは、管理スタジオを使用してテーブルの列の順序を変更するときに SQL Server が使用するのと同じアプローチです。このアプローチでは、チャンクで挿入を行い、システムに元に戻すストレスが発生しないようにし、他のユーザーがシステムにアクセスできないようにします。次に、営業時間外にオリジナルを削除し、2 番目の名前を変更し、

sp_renameの使用へのリンク。

于 2009-07-20T13:46:23.097 に答える
2

落胆して申し訳ありませんが、次のとおりです。

  • スピードアップする方法: いいえ、テーブル構造自体を変更したい場合は違います
  • それとも、営業時間外に一晩中やっているだけですか?はい、@HLGEMが指摘したように、おそらくそれが最善です
  • また、これによりテーブルロックが発生する可能性がありますか? はい

あなたには直接関係ありませんが (NOT NULL から NULL に移行するため)、このトピックに関する興味深い記事を読んでください: http://beyondrelational.com/blogs/sankarreddy/archive/2011/04/05/is-alter-table- Alter-column-not-null-to-null-always-expensive.aspx

そして最後に、いくつかの古代の歴史-2005年のフォーラムでの同等の質問で、上記の@Kevinと同じ提案が行われました-列自体をnull不可にする代わりに制約を使用します: http://www.sqlteam.com/Forums /topic.asp?TOPIC_ID=50671

于 2011-05-18T18:30:52.697 に答える