SQL Server ALTER字段NOT NULL永远需要

Chr*_*eis 10 sql sql-server ddl nullable blocking

我想从一张有大约400万条记录的表中改变一个字段.我确保所有这些字段值都是非NULL并且希望将此字段更改为NOT NULL

ALTER TABLE dbo.MyTable
ALTER COLUMN myColumn int NOT NULL
Run Code Online (Sandbox Code Playgroud)

...似乎需要永远做这个更新.有什么方法可以加快速度,或者我只是在非工作时间过夜?

这也可能导致表锁定?

kem*_*002 4

您可以更改字段并使其不为空,而无需检查字段。如果您真的担心不在下班时间执行此操作,您可以向该字段添加一个约束,以检查以确保它不为空。这将允许您使用不检查选项,而不是让它检查 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!
Run Code Online (Sandbox Code Playgroud)

实际上你有两个选择(添加了第三个选项,请参阅编辑):

  1. 使用约束将阻止更新任何新行并保持原始行不变。
  2. 将 null 行更新为其他内容,然后应用 not null alter 选项。这确实应该在非工作时间运行,除非您不介意进程被锁定在表之外。

根据您的具体情况,任一选项可能更适合您。我不会选择这个选项,因为你必须在下班时间运行它。从长远来看,与你为了节省几个小时而走捷径可能面临的麻烦相比,你在半夜更新的时间是值得的。

话虽如此,如果您打算选择第二种,您可以最大限度地减少在下班时间所做的工作量。由于您必须确保在更改列之前将行更新为不为空,因此您可以缓慢地写入游标(相对于一次完成所有操作)

  1. 遍历每一行
  2. 检查是否为空
  3. 适当更新一下。这将需要一段时间,但它不会锁定整个表并阻止其他程序访问它。(不要忘记with(rowlock)表提示!)

编辑:我只是想到了第三种选择:您可以创建一个包含适当列的新表,然后将数据从原始表导出到新表。完成此操作后,您可以删除原始表并将新表的名称更改为旧表。为此,您必须禁用对原始依赖项的依赖项,并在完成后将它们重新设置到新依赖项上,但此过程将大大减少您在非工作时间必须完成的工作量。这与您通过 Management Studio 对表进行列排序更改时 sql Server 使用的方法相同。对于这种方法,我会分块进行插入,以确保不会对系统造成撤消压力并阻止其他人访问它。然后在下班时间,您可以删除原来的,重命名第二个,并应用依赖项等。您仍然会有一些下班时间的工作,但与其他方法相比,它会微不足道。

链接到使用sp_rename

  • 如果使用 NO CHECK,则该约束将不被信任并且不能被查询优化器使用。请参阅http://sqlblog.com/blogs/tibor_karaszi/archive/2008/01/12/non-trusted-constraints-and-performance.aspx (4认同)
  • 另外,NOCHECK 关键字不适用于 NULL/NOT NULL。它仅适用于属于 CONSTRAINT 子句一部分的约束。 (3认同)