11

我想从有大约 400 万条记录的表中更改一个字段。我确保所有这些字段值都不是 NULL 并且想要将此字段更改为 NOT NULL

ALTER TABLE dbo.MyTable
ALTER COLUMN myColumn int NOT NULL

...似乎永远需要做这个更新。有什么方法可以加快速度,还是我只是在下班时间过夜?

这也可能导致表锁吗?

4

3 回答 3

4

您可以在不检查字段的情况下更改字段并使其不为空。如果您真的担心不在下班时间这样做,您可以向该字段添加一个约束,以确保它不为空。这将允许您使用 with no check 选项,而不是让它检查 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!

真的你有两个选择(添加第三个见编辑):

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

根据您的具体情况,任何一个选项都可能更适合您。我不会选择该选项,因为您必须在下班时间运行它。从长远来看,与通过走捷径节省几个小时可能面临的头痛相比,您在半夜进行更新所花费的时间将得到很好的利用。

综上所述,如果您要使用选项二,您可以最大限度地减少您在非工作时间所做的工作量。由于您必须确保在更改列之前将行更新为不为空,因此您可以将游标写入缓慢(相对于一次完成所有操作)

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

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

链接到使用sp_rename

于 2009-07-20T13:46:23.097 回答
4

我所知道的“快速”(*)执行此操作的唯一方法是

  • 创建具有所需布局的“影子”表
  • 将触发器添加到源表,以便将任何插入/更新/删除操作复制到影子表(注意捕捉任何可能弹出的 NULL!)
  • 将所有数据从源复制到影子表,可能是小块(确保您可以通过触发器处理已复制的数据,确保数据适合新结构(ISNULL(?)! )
  • 从/到其他表的所有依赖项编写脚本
  • 完成后,在显式事务中执行以下操作:
    • 在源表上获得一个排他表锁,在影子表上获得一个
    • 运行脚本以将依赖项删除到源表
    • 将源表重命名为其他名称(例如后缀 _old)
    • 将影子表重命名为源表的原始名称
    • 运行脚本以再次创建所有依赖项

您可能希望在事务之外执行最后一步,因为这可能需要相当长的时间,具体取决于引用此表的表的数量和大小,第一步根本不会花费太多时间

与往常一样,最好先在测试服务器上进行测试运行 =)

PS:请不要试图用 NOCHECK 重新创建 FK,这会使它们变得徒劳,因为优化器在构建查询计划时不会信任它们也不会考虑它们。

(*:很快归结为:停机时间最短)

于 2011-05-23T13:14:49.937 回答
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 提出了相同的建议——使用约束而不是使列本身不可为空:http ://www.sqlteam.com/Forums /topic.asp?TOPIC_ID=50671

于 2011-05-18T18:30:52.697 回答