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

Aka*_*ash 16 sql-server alter-table ddl sql-server-2012

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
Run Code Online (Sandbox Code Playgroud)

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

但是,即使在更大的表上,ALTERwithDEFAULT NOT NULL也会立即执行。有没有解释为什么这是即时的?在物理磁盘上,数据仍然需要写入所有行,对吗?

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

Aar*_*and 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与离线更改相关联的(无效!)。

在线与离线更改的 I/O

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

请注意,SQL Server 会生成一个估计计划,但它不是很有用。在所有。并且在线变更的估计计划与离线变更的估计计划相同。

在线更改计划图

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

  • +1:特别是 为“企业版”。我一直想知道为什么它在我的一些客户网站上不起作用...... (5认同)