sql-server-2008 – 快速将NULL列更改为NOT NULL

我有一个包含数百万行的表和一个允许NULL值的列.但是,当前没有行具有该列的NULL值(我可以使用查询相当快地验证这一点).但是当我执行命令时

ALTER TABLE MyTable ALTER COLUMN MyColumn BIGINT NOT NULL;

查询需要永远相对而言.它实际上需要10到20分钟,是添加检查约束的两倍多.有没有办法立即更新该列的表的元数据,特别是因为我知道没有行具有该列的NULL值?

最佳答案
@ypercube’s answer确实将此部分管理为仅元数据更改.

使用NOCHECK添加约束意味着不需要读取任何行来验证它,以及是否从列不包含NULL值的位置开始(如果您知道在检查和添加约束之间不添加任何行)然后,由于约束阻止从将来的INSERT或UPDATE操作创建NULL值,这将起作用.

但是,添加约束仍然会对并发事务产生影响. ALTER TABLE需要首先获得Sch-M锁.虽然它正在等待所有其他表访问将被阻止as described here.

一旦获得Sch-M锁,操作应该非常快.

这样做的一个问题是,即使您知道列实际上没有NULL,查询优化器也不信任约束,这意味着计划可能是次优的.

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)

以这种方式更改列定义可能遇到的一个问题是,它不仅需要读取所有行以验证它们是否满足条件,而且最终可能最终为performing logged updates to the rows.

一个可能的中途房屋可能是添加检查约束WITH CHECK.这将比WITH NOCHECK慢,因为它需要读取所有行,但它确实允许查询优化器在上面的查询中给出更简单的计划,它应该避免可能的记录更新问题.

转载注明原文:sql-server-2008 – 快速将NULL列更改为NOT NULL - 代码日志