为什么要立即添加具有默认约束的NOT NULL列?


16
CREATE TABLE TestTab (ID INT IDENTITY(1,1), st nvarchar(100))

INSERT INTO TestTab (st) values ('a')
INSERT INTO TestTab (st) values ('b')
INSERT INTO TestTab (st) values ('c')
INSERT INTO TestTab (st) values ('d')
INSERT INTO TestTab (st) values ('e')

INSERT INTO TestTab (st) SELECT TOP 10000 st from testtab
GO 30

ALTER TABLE TestTab ADD newcol nvarchar(10) DEFAULT 'newcol'
UPDATE TestTab SET newcol = 'newcol'  --6 sec
ALTER TABLE TestTab ADD newcol1 nvarchar(10) DEFAULT 'newcol1' NOT NULL

DROP TABLE TestTab

当我执行这个测试脚本中,ALTERUPDATE需要6秒,这是可以理解的。

但是,即使在更大的表上,ALTERwith DEFAULT NOT NULL语句也会立即执行。为什么这是瞬间有什么解释?在物理磁盘上,仍然需要将数据写入所有行吗?

我尝试查看SET STATISTICS IO ON和查询计划,但是这些似乎不适用于DDL操作。

Answers:


23

是的,添加具有NOT NULL的列和默认值实际上并不会在更改时将值写入所有行,因此它不再是数据大小操作。从表中选择时,实际上是从sys.system_internals_partition_columns中实现的列,这避免了必须写入所有值(直到更改它们)。请注意,这不适用于所有数据类型,并且需要企业版。

Remus Rusanu在这里对此进行了详细说明:

另外,ALTER至少由于SQL Server不产生计划,我们仍然无法显示计划,但是要查看I / O,可以使用SQL Sentry Plan Explorer。*此屏幕快照显示添加列c5 ,“ online”(如上所述)和另一列c6,“ offline”(因为不支持LOB类型)。您可以看到I / O主要表示为读取而不是写入,但是更能说明问题的是UPDATE与离线Alter关联的(无效!)。

在线与离线更改的I / O

如果您没有Enterprise Edition,则两个语句都将UPDATE附加辅助语句(以及相关的读取)。(并且,如果您使用的是没有获得完整查询调用堆栈的免费版本的Plan Explorer,您将不会看到上面的内容-您只会看到一个空的语句树。需要付费版本才能查看完整的查询调用堆栈。)

请注意,SQL Server将产生一个估计的计划,但这不是很有用。完全没有 并且,在线变更的估计计划与离线变更的估计计划相同。

在线变更的计划图

* 免责声明:我为SQL Sentry工作。


4
+1:特别是 用于“企业版”。我一直想知道为什么它在我的某些客户站点上
不起作用
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.