当一个索引依赖于某一列时,如何将该列从null更改为not null而无需重新创建索引?

10

我有一个列Column,它被声明为NULL DEFAULT(GETUTCDATE()),并且有一个包括此列的非聚集索引。我想将该列更改为NOT NULL DEFAULT(GETUTCDATE()),当我运行ALTER TABLE ALTER COLUMN语句时,SQL Azure服务说无法更改该列,因为有一个依赖于该列的索引。

这是一个生产数据库,该表保存着约1000万条记录。因此,我不想删除和重新创建索引,因为那会使数据库变慢(特别是创建索引可能需要几分钟)。

我怎样才能在不重新创建索引的情况下更改列?


相关问题:https://dev59.com/BXM_5IYBdhLWcg3wt1rD - nshah
我已在本地服务器(即非Azure)上的SQL Server 2012 SP1上进行了测试,但它也无法正常工作。因此,很可能需要删除索引并在Azure上重新创建它。 ALTER TABLE Children ALTER COLUMN ChildName VARCHAR(50) NOT NULL生成:Msg 5074,Level 16,State 1,Line 1索引“IX_Children_ChildName”依赖于列“ChildName”。Msg 4922,Level 16,State 9,Line 1 ALTER TABLE ALTER COLUMN ChildName失败,因为一个或多个对象访问此列。(当然,需要检查该列中是否有任何NULL,这将是一个错误) - Reversed Engineer
1个回答

9
表列不需要修改就能强制非空。相反,可以向表中添加新的约束条件:
ALTER TABLE [Table] WITH CHECK
   ADD CONSTRAINT [TableColumnNotNull] CHECK ([Column] Is NOT NULL);

那不会影响索引,但优化器会使用这个约束来提高性能:
CREATE TABLE Test (ID bigint PRIMARY KEY, [Column] DATE NULL DEFAULT(GETUTCDATE()));
GO --< Create test table

CREATE NONCLUSTERED INDEX TestColumnIdx ON Test ([Column]);
GO --< Create the index

ALTER TABLE Test ALTER COLUMN [Column] DATE NOT NULL;
GO --< That won't work: the index 'TestColumnIdx' is dependent on column 'Column'

Select * From Test Where [Column] Is NULL;
GO --< Check the plan: it has "Index Seek (NonClustered)"

ALTER TABLE Test WITH CHECK ADD CONSTRAINT TestColumnNotNull CHECK ([Column] Is NOT NULL);
GO --< Add a "stand-alone" NOT NULL constraint

Select * From Test Where [Column] Is NULL;
GO --< Check the plan: it has "Constant Scan" now

DROP TABLE Test;
GO --< Clean-up

2
因为它提供了符合问题设置的解决方案,所以我点赞了。但是从长远支持的角度来看,最好在不影响用户的情况下,在某个时候修改该列。 - Ryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接