NULL列をNOT NULLにすばやく変更する


11

何百万もの行とNULL値を許可する列を持つテーブルがあります。ただし、現在、その列にNULL値を持つ行はありません(クエリでこれをかなり迅速に確認できます)。ただし、コマンドを実行すると

ALTER TABLE MyTable ALTER COLUMN MyColumn BIGINT NOT NULL;

クエリは比較的長い時間かかります。実際には10〜20分かかり、チェック制約を追加する場合の2倍以上の時間がかかります。特にその列にNULL値を持つ行がないことを知っているので、その列のテーブルのメタデータを即座に更新する方法はありますか?


2
いいえ(または、少なくとも文書化された/サポートされている方法を使用していない)。ALTER COLUMN to NOT NULLが大量のログファイルの成長を引き起こす理由を
マーティンスミス

2
また、Sch-M「永久に」ロックを待機している可能性もあります。待っていたのか忙しいのか見ていましたか?
マーティンスミス

@MartinSmith私は永遠に私が意味することを明確にしました。他のセッションがデータベースにヒットしない開発環境でこれをテストしています。最終的に完了します。しかし、あなたがリンクした答えは、なぜそんなに時間がかかるのかを説明しています。コメントを答えとして言い換えることができれば、私はそれを受け入れます。
ジョセフデイグル

回答:


12

@ypercubeの答えは、メタデータのみの変更としてこれを部分的に管理します。

制約を追加NOCHECKすると、検証のために行を読み取る必要がなくなり、列にNULL値が含まれていない位置から開始する場合(および制約のチェックと追加の間に何も追加されないことがわかっている場合)、制約によりNULL、将来INSERTまたはUPDATE操作から値が作成されないため、これは機能します。

ただし、制約を追加すると、並行トランザクションに影響を与える可能性があります。ALTER TABLE取得する必要があります。Sch-M最初のロックを。これを待っている間、他のすべてのテーブルアクセスは、ここで説明するようにブロックされます

Sch-Mただし、ロックが取得されると、操作は非常に高速になります。

これに関する問題の1つは、実際に列にNULLs がないことがわかっていても、クエリオプティマイザーによって制約が信頼されないことです。つまり、計画が準最適になる可能性があります。

CREATE TABLE T (X INT NULL)

INSERT INTO T 
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM master..spt_values

ALTER TABLE T WITH NOCHECK
  ADD  CONSTRAINT X_NOT_NULL 
    CHECK (X IS NOT NULL) ; 

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

予定

これをより単純なものと比較してください

ALTER TABLE T ALTER COLUMN X INT NOT NULL

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

予定

この方法で列定義を変更する際に発生する可能性のある問題の1つは、すべての行を読み取って条件を満たしていることを確認する必要があるだけでなく、実際に行の更新をログに記録できることです。

考えられる半分の方法は、チェック制約を追加することWITH CHECKです。これは、WITH NOCHECKすべての行を読み取る必要があるため遅くなりますが、クエリオプティマイザーが上記のクエリでより単純なプランを提供できるようにし、ログに記録される更新の問題を回避する必要があります。


7

列を変更する代わりにCHECKNOCHECKオプションでテーブル制約を追加できます。

ALTER TABLE MyTable WITH NOCHECK
  ADD  CONSTRAINT MyColumn_NOT_NULL 
    CHECK (MyColumn IS NOT NULL) ;

1
これにより、列を作成するNULLがクエリオプティマイザーが使用できない将来の更新または挿入が防止されます。
マーティンスミス

@MartinSmithそうそう、同じ質問の答えとコメントを読んだだけです。SQLServerの大きなテーブルにNOT NULL列を追加するにはどうすればいいですか。問題またはより良い解決策の答えを追加してください、私は私のものを削除します。
ypercubeᵀᴹ

2
より良い解決策はありません。部分的な解決策を提供するため、これを支持しました。すべてのOPはをしたい場合は、無効なデータを防ぐことが動作します(と速くよりでなければなりませんALTER COLUMN一度としてSch-Mロックが取得され、これはまったくの行をスキャンする必要はありません)。ただ、それは(に使用している場合例えば全く同じではないことを指摘しNOT INたクエリプランがより複雑になります)
マーティン・スミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.