考虑以下空(如无行)表:
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;
这种行为的理由是什么?在内部尝试执行的数据库是什么,直接添加列失败?我觉得它可能与内部版本控制有关,但我在这方面找不到任何东西。
这是猜测。我猜Sybase正在过于保守。通常,您不能将没有not null
值的新default
列添加到具有行的表中。在所有数据库中都是如此,因为无法填充新列的现有行。
我猜Sybase只是不检查表是否有行,只有它存在。显然它没有检查alter
。
这只是推测,但我怀疑它必须做到需要同时获取整个表上的锁以确保继续遵守模式,并为记录重新分配空间的组合。
如果没有默认值,允许直接添加NOT NULL
列会损害任何现有记录。是的,我们知道桌子是空的。并且数据库可以(最终)知道表在执行时是空的......但是在执行计划编译时它不能真正知道表是空的,因为在确定执行计划时可以添加行。
这意味着数据库需要生成最坏的执行计划,包括锁定整个表,以便查询以事务安全的方式运行。此外,添加(或删除)列会导致数据库的额外工作,因为它需要重新分配任何页面并重建索引,以便考虑单个记录的更改大小。
将两者放在一起,很难只回滚失败的查询,因为您可能有不同状态的实际页面。无论出于何种原因,开发人员选择不允许这样做。
其他选项允许您在错误的行阻碍并违反模式时简单地使查询失败,因为您没有在页面内重新调整记录大小。它甚至可以让你逃脱一些页面和行锁,而不是完整的表锁。