为什么某些 DBMS 不允许回滚某些 DDL 语句?

Jor*_*ril 21 feature-comparison database-agnostic ddl rollback

最近我发现 MySQL支持回滚 DDL,例如“alter table”... 习惯了 PostgreSQL,这让我感到奇怪,但我的一个朋友告诉我,即使是 Oracle 也不允许它..不支持它是否有技术原因?对他们来说,这只是一个“无趣”的功能吗?

编辑:刚刚发现这个比较。它看起来像有很多的DBMS是支持事务DDL。

Pet*_*aut 19

这在 PostgreSQL 中起作用的原因是系统目录是常规表。因此,例如,创建一个新函数只需要在pg_proc表中插入一行,更改列的默认值只需要更新 中的某行pg_attrdef,依此类推。由于表无论如何都是事务性的,因此您几乎不得不竭尽全力不让它以这种方式工作。(这里省略了许多痛苦的实现细节。;-))

我想,在不知道源代码的情况下,其他数据库引擎使用一些自定义的内部结构来表示它们的系统目录信息。因此,他们必须付出额外的努力,可能需要付出很多额外的努力,才能使事务性 DDL 发挥作用,而这显然不是他们的首要任务。

另一方面,这也是 PostgreSQL 大版本升级如此痛苦的原因。其他产品大概可以在设计其内部元数据结构时考虑更改和更新,因此升级到新的主要版本没有问题。在 PostgreSQL 中,无法将系统目录表更改为突然看起来像系统目录表的较新版本,至少在保持系统在线时无法更改,因为这需要访问系统目录。呃。

  • 好吧,我更喜欢我的数据库始终处于一致的状态,而不是易于数据库版本升级,但我想这是一个意见问题:)感谢您的解释! (2认同)

小智 10

大多数没有?无赖。

我主要使用 SQL Server,它确实如此。我知道甲骨文没有,但我认为甲骨文可能是一个畸变。

在 SQL Server 中,我很确定您可以在单个事务中运行多个 DDL 语句,尽管我也认为有一些限制(我都忘记了)。如果您愿意,您可以创建或更改或删除大多数内容并将其回滚。Red-Gate SQL Compare(我喜欢的一个工具)利用了这一点。

这样做的问题是您的事务范围变得相当有趣……当您在更新事务 (DDL) 中涉及系统目录时,您冒着获取一些非常重要的锁的风险,并且您可能会阻止对系统目录的访问。如果他们的查询在目录中找不到他们的表,用户将无能为力!

不过,总的来说,能够在多语句事务中包含 DDL 是很方便的。

更有用的是,SQL Server DDL 命令TRUNCATE 也可以是多语句事务的一个元素。您可以截断目标表(非常快),构建它,然后如果您喜欢结果,则进行提交。如果出现问题,您会回滚,瞧!就好像您从未打扰过桌子一样。日志空间也被最小化。我经常利用这一点。

  • [这是一个答案](http://dba.stackexchange.com/questions/4356/how-to-use-transactions-with-sql-server-ddl/4357#4357) 显示了一个事务绑定 DDL 的例子SQL 服务器。另外,我一直认为`TRUNCATE`不能回滚。我错了。 (2认同)

Mar*_*ian 5

在 SQL Server 中,我们可以回滚 DDL 语句,它不会在语句末尾使用自动提交。在其他 DBMS 中我不知道,但我记得在 Oracle 中不能这样做。我相信它特定于每个 DBMS,不确定 SQL 标准对此有何看法,但我确信没有生产者实现 100% 的标准。

SO 上有一个类似的问题:是否可以在事务中(在 SQL Server 中)运行多个 DDL 语句?


Gar*_*ary 5

Oracle 具有共享查询解析功能,因此一个会话执行的 SELECT * FROM table_a(通常)与另一个会话的执行相同。如果一个会话认为表中有十列而另一会话认为有十一列,那将会中断。

  • 顺便说一句,11gR2 版本引入了版本的概念来协助热升级。有效的现有连接使用一个版本(有五列)。您开始一个新版本,添加一个专栏并使用新版本为新会话开始一些新连接。一旦所有未完成的会话都完成了,旧版本就会变得陈旧,一切都使用新版本。没有回滚,但在新版本一切正常之前,您不会在新版本上放置新活动。 (2认同)