【问题标题】:Sybase ASE: Add NOT NULL column without a DEFAULT fails. Why?Sybase ASE:添加不带 DEFAULT 的 NOT NULL 列失败。为什么?
【发布时间】:2019-02-04 14:18:46
【问题描述】:

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

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;

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

【问题讨论】:

  • 我建议您再次运行测试,但这次在表格中包含一些数据;回复我们哪些命令成功与失败......这应该让您对正在发生的事情有更多的了解(例如,该命令是否只是修改架构?是该命令创建一个新表并从旧表复制数据?是在解析/编译阶段产生的错误信息吗?是在执行阶段产生的错误信息吗?)
  • 这是众所周知的,并且很明显为什么您不能在没有 DEFAULT 的情况下将 NOT NULL 列添加到已经有行的表中,这是因为引擎需要一个值来填充先前存在的新行柱子。我的问题是关于为什么这会发生在一个空的表上。

标签: sql sybase default-value sap-ase


【解决方案1】:

这只是推测,但我怀疑它必须结合两者获取整个表的锁以保证持续符合架构, 为记录重新分配空间。

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

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

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

其他选项允许您在错误行妨碍查询并违反架构时简单地使查询失败,因为您没有重新调整页面内记录的大小。它甚至可以让您摆脱一些页锁和行锁,而不是全表锁。

【讨论】:

  • 这个答案与原来的答案大不相同。如果你之前读过它,你可能想再读一遍。现在更有意义了。
  • 这不会影响 ALTER TABLE 从列中删除 NULL 限制吗?因为它按预期工作,所以它只是一个 NOT NULL 列的添加失败。
  • 不,因为删除限制不会改变数据的大小。数据库可以通过正常回滚来执行正常错误查询。即使删除会改变数据大小的整个列也是可以的,因为不存在违反架构的坏数据的风险。
【解决方案2】:

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

我猜 Sybase 根本不检查表是否有行,只检查它是否存在。显然它没有检查alter

【讨论】:

  • 这并不能解释为什么您可以先将字段添加为 NOT NULL,然后再立即使用 ALTER TABLE 将字段设置为 NULL。它仍然是 ALTER TABLE,其他一切都一样。
  • @JosephSabido 。 . .代码的一个分支检查表是否存在。另一个检查表是否有行。你说得对,它们不一致。
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 2021-06-12
  • 1970-01-01
  • 2014-11-15
  • 1970-01-01
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多