考虑以下空表(如无行):
CREATE TABLE my_table(
my_column CHAR(10) NOT NULL
);
尝试添加不带DEFAULT的NOT NULL列将失败:
ALTER TABLE my_table ADD my_new_column CHAR(10) NOT NULL;
Error:
*[Code: 4997, SQL State: S1000]
ALTER TABLE my_table failed.
Default clause is required in order to add non-NULL column 'my_new_column'.
但是将列添加为NULL,然后将其更改为NOT NULL将会起作用:
ALTER TABLE my_table ADD my_new_column CHAR(10) NULL;
ALTER TABLE my_table MODIFY my_new_column CHAR(10) NOT NULL;
设置默认值然后删除默认值也可以:
ALTER TABLE my_table ADD my_new_column CHAR(10) DEFAULT '' NOT NULL;
ALTER TABLE my_table REPLACE my_new_column DEFAULT NULL;
此行为的理由是什么?直接添加该列失败的数据库在内部尝试做什么?我觉得这可能与内部版本控制有关,但是我在这方面找不到任何东西。
答案 0 :(得分:0)
这只是推测,但我怀疑它必须同时进行和两个操作,以获取对整个表的锁定,以确保继续符合架构,和为记录重新分配空间。
如果没有默认值,则允许直接添加NOT NULL
列将损害任何现有记录。是的,我们知道该表为空。并且数据库可以(最终)知道表在执行时为空 ...,但是它并不能真正知道表在执行计划编译时为空,因为可以在执行计划时添加一行。确定执行计划。
这意味着数据库将需要生成最糟糕的执行计划,包括对整个表进行锁定,以使查询以事务安全的方式运行。此外,添加(或删除)列会为数据库带来额外的工作,因为它需要重新分配任何页面并重建索引,以解决各个记录的更改大小。
将两者放在一起,很难回滚失败的查询,因为您的实际页面可能处于不同的状态。无论出于何种原因,开发人员都选择不允许这样做。
如果您不调整页面中的记录大小,则其他选项可让您简单地使查询失败(如果有问题的行阻塞了并违反了架构),则查询失败。它甚至可以让您摆脱一些页和行锁,而不是完整的表锁。
答案 1 :(得分:0)
这是猜测。我猜想Sybase过于保守了。通常,您不能将没有not null
值的新default
列添加到具有行的表中。在所有数据库中都是如此,因为无法填充新列的现有行。
我猜想Sybase只是不检查表是否有行,而仅检查它是否存在。显然,它没有对alter
进行检查。