将列添加到生产表


28

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

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

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

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


1
关于此问题的最新文章:sqlservercentral.com/articles/Change+Tracking/74397
8kb

Answers:


27

“这取决于”

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

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

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

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

我已经更改了数十亿行表,这些表花了几秒钟来添加可为空的列。

我是否说要先备份?


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

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

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

21

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

  • 将列添加为NULLable-在大多数情况下应该很快
  • 将值更新为默认值
    • 您可以根据需要分批进行此操作
    • 您还可以使用它来应用条件逻辑,其中某些行可能无法获得默认值
  • 添加非空/默认约束
    • 当所有数据都不为NULL时,这将更快,但仍可测量

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


最后一点:•add the not null/default constraints我不确定这没有潜在的问题...当MSSQL(甚至2008R2)将not null列更改为null时,如果在其上放置跟踪,则实际上可以看到它的内容对表的每一行进行完全更新,即update table1 set column1 = column1我假设它以一种完全愚蠢的方式进行非空验证。该事务是表大小的两倍(在页面之前和之后),因此对于DW表来说可能是巨大的。以前我们不得不BCP数据出来,然后截断,做到空非空的变化,然后BCP英寸

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

嘿@Mike,这听起来像是一个很好的潜在问题。
德里克·唐尼

4

你有没有考虑过:

  1. 创建一个新表,其中包括对表定义所做的更改。
  2. 插入新表定义中,从原始表中选择。
  3. 将原始表重命名为_orig,然后将新表重命名为原始表名。

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

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


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

那是我的想法,当时我戴着数据仓库帽,可以轻松地控制更改。在OLTP情况下,您是对的,必须使用写锁定,以避免对表进行更改。
RobPaller 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.