我想从一张有大约400万条记录的表中改变一个字段。我确保所有这些字段值都是非NULL并且希望将此字段更改为NOT NULL
ALTER TABLE dbo.MyTable
ALTER COLUMN myColumn int NOT NULL
...似乎需要永远做这个更新。有什么方法可以加快速度,或者我只是在非工作时间内一夜之间停止工作?
这也可能导致表锁定吗?
答案 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!
你真的有两个选择(添加第三个选项见编辑):
根据您的具体情况,任一选项可能对您更好。我不会选择这个选项,因为你必须在非工作时间运行它。从长远来看,你在半夜进行更新所花费的时间与使用快捷方式可能会面临的头痛相比可以节省几个小时。
总而言之,如果您打算使用选项2,您可以最大限度地减少您在非工作时间所做的工作量。由于您必须确保在更改列之前将行更新为非null,因此可以将游标写入缓慢(相对于一次执行所有操作)
编辑:我刚想到了第三种选择: 您可以使用适当的列创建新表,然后将原始表中的数据导出到新表。完成此操作后,您可以删除原始表并将新表的名称更改为旧表。要做到这一点,你必须禁用原始的依赖项,并在完成后将它们重新设置为新的,但是这个过程将大大减少你在非工作时间必须完成的工作量。这与通过管理工作室对表进行列排序更改时sql server使用的方法相同。对于这种方法,我会以块的形式进行插入,以确保不会对系统造成撤消压力并阻止其他人访问它。然后在非工作时间,你可以放弃原件,重命名第二个,并应用依赖关系等。你仍然会有一些非工作时间工作,但与其他方法相比,这将是微不足道的。
使用sp_rename链接。
答案 1 :(得分:4)
我知道的“快速”(*)的唯一方法是
您可能希望在事务之外执行最后一步,因为它可能需要相当长的时间,具体取决于引用此表的表的数量和大小,第一步不会花费太多时间
与往常一样,最好先在测试服务器上进行测试运行=)
PS:请不要试图用NOCHECK重新创建FK,它会使它们徒劳无功,因为优化器不会信任它们,也不会在构建查询计划时考虑它们。
(*:快速归结为:停机时间最短)
答案 2 :(得分:2)
对于沮丧感到抱歉,但是:
与您没有直接关系(因为它是关于从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