在SQL Server 2008 R2上的大型生产表中添加列的最佳方法是什么?根据Microsoft的在线丛书:


立即执行ALTER TABLE中指定的更改。如果更改需要修改表中的行,则ALTER TABLE将更新行。 ALTER TABLE在表上获取模式修改锁,以确保更改期间没有其他连接甚至引用该表的元数据,但在线索引操作的末尾需要非常短的SCH-M锁。


(http://msdn.microsoft.com/zh-cn/library/ms190273.aspx)

在具有数百万行的大型表上,这可能需要一段时间。停电是唯一的选择吗?解决这种情况的最佳方法是什么?

评论

有关此问题的最新文章:sqlservercentral.com/articles/Change+Tracking/74397

#1 楼

“取决于”

如果您添加不需要向行中添加数据的列,那么它可以很快。

例如,添加int或char需要物理行移动。不应添加没有默认值的可为空的varchar(除非需要扩展NULL位图)

您需要在恢复的生产副本上进行尝试以获得估算值

如果必须在十亿行表上重新添加索引和键,则创建新表,复制,重命名可能会花费更长的时间。

我更改了十亿行表,花了几秒钟的时间来添加可为空的表专栏。

我说要先备份吗?

评论


在备份上+1。并确保您也有足够的日志空间。

–SqlACID
2011年8月9日在20:28

您能否阐明为什么添加int或char需要物理行移动?

–sh-beta
2011年8月10日17:41

您是说“不需要”要求将数据添加到第二行中的行吗?

–本·布罗卡(Ben Brocka)
2012年3月1日14:42

#2 楼

如果该列可为NULL,则影响应该可以忽略不计。如果该列不能为NULL,并且必须设置该值,那么它可能会大不相同。在这种情况下,我要做的是,而不是一次性添加非null和默认约束,而是将数据有效地添加到每一行:


将列添加为NULLable-应该很快在大多数情况下
将值更新为默认值

您可以在必要时分批执行此操作
您还可以使用它来应用条件逻辑,其中某些行可能无法获得默认值


添加非null /默认约束

当所有数据都不为NULL时这将更快,但仍可测量

/>

同意@gbn,您可以通过还原生产副本并在那里进行测试来进行测试...您会很好地把握时间(假设硬件有些相似),并且还可以查看对事务日志的影响。

评论


最后一点:•添加非null /默认约束我不确定这没有潜在的问题...当MSSQL(甚至2008R2)将not null列更改为null时,如果在您实际上可以在表的内部看到它,对表的每一行进行了完全更新,即update table1 set column1 = column1我认为它是以一种完全愚蠢的方式进行非空验证。该事务是表大小的两倍(在页面之前和之后),因此对于DW表来说可能是巨大的。以前,我们不得不将bcp数据输出,截断,将null更改为非null,然后将bcp输入。

–user7116
2012年3月1日14:23



如果有人知道解决这个问题的方法,我很想知道...相反,在Oracle中,将null更改为not null会执行锁定,然后执行选择操作以验证是否非null,然后进行瞬时的纯元数据更新。

–user7116
2012年3月1日14:23



嘿@Mike,这听起来像是一个很好的潜在问题。

–德里克·唐尼(Derek Downey)
2012年3月1日15:18

#3 楼

您是否考虑过:


创建一个包含对该表所做的更改的新表

插入到原来的表中选择的新表定义
表。
将原始表重命名为_orig,然后将新表重命名为原始表名。

这里的缺点是您必须在表中留出足够的空间。数据库进行此更改。您可能仍然需要在表上具有读锁定,以防止任何脏读。

但是,如果有机会或需要同时访问原始表,则可以最大程度地减少对最终用户的影响。它还应尽量减少锁定时间。

评论


您是否需要写锁定而不是读?用户可以在旧表中看到数据,这很好,您只是不想让他们提交任何更改,这些更改在完成缓冲区交换后会被覆盖。

–万事通
2011年10月4日在21:05

那是我的想法,我戴着数据仓库的帽子,可以轻松地控制更改。在OLTP情况下,您是对的,必须使用写锁定,以避免对表进行更改。

– RobPaller
2011年10月5日13:48

#4 楼

我有一个特殊的例外,我应该提到。

对于SQL Server 2012 Enterprise和更高版本,添加带有运行时常量的新NOT NULL列是一项联机操作,该操作会立即完成,并且不依赖于有关表中行数的信息。

有关此信息的更多信息,请参见MSDN

我将重述重要部分。 />从SQL Server 2012(11.x)Enterprise Edition开始,当
默认值为运行时常量时,添加具有默认值的NOT
表中的行数很多,该操作几乎是立即完成的。因为,表中的现有行在操作期间不会更新。相反,默认值仅存储在表的
元数据中,并根据需要在访问这些行的
查询中查找该值。