PostgreSQL 中的事务性 DDL:竞争分析

来自 PostgreSQL wiki
跳转到导航跳转到搜索

事务性 DDL

与一些商业竞争对手类似,PostgreSQL 的一个更高级的功能是它能够通过其 预写日志 设计执行事务性 DDL。这种设计支持撤销对 DDL 的重大更改,例如创建表。你无法从对数据库或表空间的添加/删除操作中恢复,但所有其他目录操作都是可逆的。

PostgreSQL

以下是一个示例,展示了 PostgreSQL 设计在这一方面的强大功能(感谢 Nigel McNie 提供了该示例以及下面的 MySQL 示例)。

$ psql mydb
mydb=# DROP TABLE IF EXISTS foo;
NOTICE: table "foo" does not exist
DROP TABLE
mydb=# BEGIN;
BEGIN
mydb=# CREATE TABLE foo (bar int);
CREATE TABLE
mydb=# INSERT INTO foo VALUES (1);
INSERT 0 1
mydb=# ROLLBACK;
ROLLBACK
mydb=# SELECT * FROM foo;
ERROR: relation "foo" does not exist
mydb=# SELECT version();
version
----------------------------------------------------------------------
PostgreSQL 8.3.7 on i386-redhat-linux-gnu, compiled by GCC gcc (GCC) 4.3.2 20081105 (Red Hat 4.3.2-7)
(1 row)

经验丰富的 PostgreSQL DBA 知道如何利用此功能来保护自己在执行复杂操作(如模式升级)时。如果你将所有这些更改放入一个事务块中,你可以确保它们原子地应用或完全不应用。这极大地降低了数据库因模式更改中的拼写错误或其他类似错误而损坏的可能性,这一点在修改多个相关表时尤为重要,因为错误可能会破坏关系键。

MySQL

如果你使用的是 MySQL,则 DDL 和一些类似更改无法以这种方式撤销。如果你使用的是 MyISAM,则根本没有回滚可用。使用 InnoDB 时,服务器有一个 隐式提交,即使正常自动提交行为被关闭,也会发生。值得注意的是,在 5.0 版本中,你遇到隐式提交行为的范围甚至在扩展;你可以自行推断这意味着什么,关于早期版本的提交可靠性。以下是如何在最近的 MySQL 版本中执行相同的过程。

mysql> drop table if exists foo;
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> create table foo (bar int) type=InnoDB;
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> insert into foo values (1);
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from foo;
+------+
| bar |
+------+
| 1 |
+------+
1 row in set (0.00 sec)

mysql> select version();
+--------------------------+
| version() |
+--------------------------+
| 5.0.32-Debian_7etch1-log |
+--------------------------+
1 row in set (0.00 sec)

你还应该知道,由于它们的实现方式,MySQL 中的回滚执行速度比原始插入慢得多。

在 5.5(并且关闭了自动提交)中,情况不再如此。

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> drop table foo;
Query OK, 0 rows affected (0.02 sec)

mysql> create table foo (bar int) engine=InnoDB;
Query OK, 0 rows affected (0.08 sec)

mysql> insert into foo values (1);
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.02 sec)

mysql> select * from foo;
Empty set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.8     |
+-----------+
1 row in set (0.05 sec)

Oracle

从 Oracle Database 11g Release 2 开始,Oracle 支持 基于版本的重新定义,它提供对模式对象的数据库范围版本控制,以支持在生产环境中应用程序的在线测试和升级。除了使用该功能或在早期版本中,根据 事务管理,“事务在以下情况下结束...用户运行 DDL 语句,例如 CREATE、DROP、RENAME 或 ALTER。如果当前事务包含任何 DML 语句,则 Oracle 首先提交事务,然后运行并提交 DDL 语句作为新的单语句务。”以及“在应用程序正常终止或完成数据定义语言 (DDL) 操作后发生隐式请求。”

SQL Server

SQL Server 在某些情况下支持事务性 DDL。如果你在读已提交隔离模式(悲观)下运行 SQL Server,这是默认模式,你可以使用事务性 DDL SQL Server 支持事务性 DDL。如果你正在运行 SQL Server 2005 或更高版本,并且在快照隔离模式(乐观)下运行,则对在显式事务中支持哪些 DDL 有限制 SQL Server 快照隔离事务性 DDL 约束

“SQL Server 不支持元数据版本控制。因此,在快照隔离下运行的显式事务中,可以执行哪些 DDL 操作存在限制。以下 DDL 语句在快照隔离下不允许在 BEGIN TRANSACTION 语句之后执行:ALTER TABLE、CREATE INDEX、CREATE XML INDEX、ALTER INDEX、DROP INDEX、DBCC REINDEX、ALTER PARTITION FUNCTION、ALTER PARTITION SCHEME 或任何公共语言运行时 (CLR) DDL 语句。当你使用快照隔离在隐式事务中时,这些语句是允许的。隐式事务,顾名思义,是指单个语句,它使即使使用 DDL 语句也可以强制执行快照隔离的语义。违反此原则会导致错误 3961:“快照隔离事务在数据库 '%.*ls' 中失败,因为自该事务开始以来,语句访问的对象已由另一个并发事务中的 DDL 语句修改。由于元数据没有版本控制,因此不允许这样做。如果与快照隔离混合使用,对元数据的并发更新会导致不一致。”

Sybase Adaptive Server

Sybase Adaptive Server 支持事务性 DDL。.

DB2 UDB

DB2 支持事务性 DDL。.

Informix

Informix 支持事务性 DDL。(感谢 Digital Globe 的 Gregory Williamson 提供此示例)。

SQL: New Run Modify Use-editor Output Choose Save Info Drop Exit
Modify the current SQL statements using the SQL editor.
----------------------- mydb@myserver ------ Press CTRL-W for Help --------
drop table foo;

111: ISAM error: no record found. Not in the database.

===
BEGIN;

Started transaction.

===
create table foo (bar int);

Table created.

===
insert into foo values (1);

1 row(s) inserted.

===
rollback;

Transaction rolled back.

===
select * from foo;

111: ISAM error: no record found. Not in the database.

(exit from dbaccess)

myserver% dbschema -v
INFORMIX-SQL Version 9.30.UC1

Firebird (Interbase)

Firebird/Interbase 也 支持事务性 DDL