2009-07-20 51 views
10

我想从包含约400万条记录的表中更改字段。我保证,所有这些字段的值是NOT NULL,并希望改变这个领域NOT NULLSQL Server ALTER字段NOT NULL需要永久

ALTER TABLE dbo.MyTable 
ALTER COLUMN myColumn int NOT NULL 

...似乎采取永远做此更新。任何加速它的方法,或者我坚持只是在非工作时间过夜吗?

也可能导致表锁?

+1

个人而言,我决不会在任何非高峰时段的任何时间使现有的大表更改表结构。即使它很快,它也可能导致用户在做出更改时出现问题的地方执行操作。 任何重大更改最好在单用户模式下完成。当用户不能做任何事情(在课程之前和在非高峰时段宣布)时,最好有一个预定的维护时间段,而不是有不快乐的用户正在做一些出错的事情。 – HLGEM 2009-07-20 14:11:51

+0

您正在改变的列是否涉及FK约束? – onupdatecascade 2009-07-22 16:44:43

+1

从分析器中的快速测试中,它需要在表格上使用`Sch-M`锁定[基本上与所有内容不兼容](http://msdn.microsoft.com/zh-cn/library/ms186396.aspx)。然后它必须读取每一页以确定所有行都有效。 – 2011-05-18 18:44:46

回答

4

您可以在没有检查字段的情况下更改字段并使其不为空。如果你真的担心没有关闭数小时,你可以添加一个约束到该字段,该字段进行检查以确保它不是null。这将允许您使用没有检查选项,并且不会检查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. 更新其他值为空的行,然后应用not null alter选项。这真的应该在下班时间运行,除非你不介意进程被锁定在表外。

根据您的具体情况,任一选项可能对您更好。我不会选择这个选项,因为你必须在下班时间运行它。从长远来看,在半夜进行更新的时间将会花费很多,比较一下您可能会遇到的头痛问题,通过捷径来节省几个小时。

这一切都说,如果你打算去选择两个,你可以最大限度地减少你在下班时间的工作量。因为你必须确保你改变了列之前更新的行不为空,你可以写一个光标慢慢(相对于一次做这一切)

  1. 去的每一行
  2. 检查看看如果它为空
  3. 适当更新它。 这将需要很长时间,但它不会锁定整个表格阻止其他程序访问它。 (不要忘了with(rowlock)表提示!)

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

链接到使用sp_rename

2

对不起,我沮丧,但:

  • 加快它的任何方式:不,不,如果你想改变表结构本身
  • 还是我在摘卡住只是做一夜小时?是的,这可能是最好的,因为@HLGEM指出
  • 也可能导致表锁?是

不是直接在这个话题你有关(因为这是关于不会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

4

只有这样,才能做到这一点“快”(*),我知道的是

  • 创建一个具有所需布局的“阴影”表
  • 向源表中添加触发器,以便将任何插入/更新/删除操作复制到阴影表中(介意捕获可能弹出的任何NULL)!
  • 将所有数据从源复制到影子表中,可能以小块(确保您可以通过触发器处理已复制的数据,确保数据符合新结构(ISNULL( ?))
  • 脚本的所有依赖自/至其他表
  • 当一切都完成后,请执行下列操作一个明确的事务里!
    • 坐上shadowtable
    • 在源表的独占表锁和一个运行脚本下降依赖于源表
    • 源表重命名为其他(如后缀_OLD)
    • 影子表重命名为源表的原始名称
    • 运行脚本来创建所有再次

你可能想要做一个交易外的最后一步的依赖关系s可能需要相当长的时间,具体取决于引用该表的表的数量和大小,第一步根本不需要太多时间

与往常一样,最好在测试上进行测试运行PS:请不要试图用NOCHECK重新创建FK,它会使它们无用,因为优化器不会信任它们,也不会在构建查询计划时考虑它们。

(*:其中快速归结为:以最少的停机时间)