SQL Server ALTER字段NOT NULL永远需要

时间:2009-07-20 13:42:37

标签: sql sql-server nullable blocking ddl

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

ALTER TABLE dbo.MyTable
ALTER COLUMN myColumn int NOT NULL

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

这也可能导致表锁定吗?

3 个答案:

答案 0 :(得分: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选项。这真的应该在非工作时间运行,除非你不介意进程被锁定在表外。
  3. 根据您的具体情况,任一选项可能对您更好。我不会选择这个选项,因为你必须在非工作时间运行它。从长远来看,你在半夜进行更新所花费的时间与使用快捷方式可能会面临的头痛相比可以节省几个小时。

    总而言之,如果您打算使用选项2,您可以最大限度地减少您在非工作时间所做的工作量。由于您必须确保在更改列之前将行更新为非null,因此可以将游标写入缓慢(相对于一次执行所有操作)

    1. 浏览每一行
    2. 检查是否为空
    3. 适当更新。 这将花费很长时间,但它不会锁定整个表阻止其他程序访问它。 (不要忘记with(rowlock)表提示!)
    4. 编辑:我刚想到了第三种选择:   您可以使用适当的列创建新表,然后将原始表中的数据导出到新表。完成此操作后,您可以删除原始表并将新表的名称更改为旧表。要做到这一点,你必须禁用原始的依赖项,并在完成后将它们重新设置为新的,但是这个过程将大大减少你在非工作时间必须完成的工作量。这与通过管理工作室对表进行列排序更改时sql server使用的方法相同。对于这种方法,我会以块的形式进行插入,以确保不会对系统造成撤消压力并阻止其他人访问它。然后在非工作时间,你可以放弃原件,重命名第二个,并应用依赖关系等。你仍然会有一些非工作时间工作,但与其他方法相比,这将是微不足道的。

      使用sp_rename链接。

答案 1 :(得分:4)

我知道的“快速”(*)的唯一方法是

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

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

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

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

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

答案 2 :(得分: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