Sybase ASE:添加没有默认值的NOT NULL列失败。为什么?

时间:2018-08-29 17:48:05

标签: sql sybase default-value sybase-ase

考虑以下空表(如无行):

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;

此行为的理由是什么?直接添加该列失败的数据库在内部尝试做什么?我觉得这可能与内部版本控制有关,但是我在这方面找不到任何东西。

2 个答案:

答案 0 :(得分:0)

这只是推测,但我怀疑它必须同时进行两个操作,以获取对整个表的锁定,以确保继续符合架构,为记录重新分配空间。

如果没有默认值,则允许直接添加NOT NULL列将损害任何现有记录。是的,我们知道该表为空。并且数据库可以(最终)知道表在执行时为空 ...,但是它并不能真正知道表在执行计划编译时为空,因为可以在执行计划时添加一行。确定执行计划。

这意味着数据库将需要生成最糟糕的执行计划,包括对整个表进行锁定,以使查询以事务安全的方式运行。此外,添加(或删除)列会为数据库带来额外的工作,因为它需要重新分配任何页面并重建索引,以解决各个记录的更改大小。

将两者放在一起,很难回滚失败的查询,因为您的实际页面可能处于不同的状态。无论出于何种原因,开发人员都选择不允许这样做。

如果您不调整页面中的记录大小,则其他选项可让您简单地使查询失败(如果有问题的行阻塞了并违反了架构),则查询失败。它甚至可以让您摆脱一些页和行锁,而不是完整的表锁。

答案 1 :(得分:0)

这是猜测。我猜想Sybase过于保守了。通常,您不能将没有not null值的新default列添加到具有行的表中。在所有数据库中都是如此,因为无法填充新列的现有行。

我猜想Sybase只是不检查表是否有行,而仅检查它是否存在。显然,它没有对alter进行检查。