在ITPUB上看到有人提出了这个问题。在Sqlserver或一些其余的数据库中,DDL语句也是能够回滚的,那么Oracle为何不能回滚DDL语句呢。html
这个问题来自:http://www.itpub.net/thread-1300088-1-5.html数据库
要说明这个问题,首先须要说明什么是DDL语句。DDL语句是数据定义语句,包括各类数据对象的建立、修改和删除,以及受权等操做。并发
在Oracle中DDL语句将转化为修改数据字典表的DML语句。一个简单的修改表的DDL语句,会致使Oracle在后台经过递归SQL语句进行大量的查询和修改的操做。spa
若是有兴趣,能够经过SQL_TRACE根据一下DDL语句,检查一下Oracle后台实际执行了哪些操做。.net
在Oracle中,Oracle执行DDL前会发出一个COMMIT语句,而后执行DDL操做,最后再发出一个COMMIT操做。设计
前面提到了对于Oracle而言,DDL其实是数据字典表的一系列的修改,也就是数据字典表的DML操做,那么理论上讲Oracle是彻底有能力实现DDL语句的回滚的,那么Oracle为何设计成如今的工做方式。要知道Oracle以灵活和强大的可定制性著称,可是Oracle没有给用户任何回滚DDL的可能性,显示是存在着十分充分的理由。server
首先分析一下Oracle为何要在DDL语句以前和以后各执行一次COMMIT,其实道理很简单,Oracle是为了将用户的读写操做和数据字典的修改隔离开,用户数据的读写不该该和数据字典的操做放在同一个事务中。htm
为了说明Oracle为何不回滚DDL语句,下面假设Oracle能够回滚DDL语句,看看这会给Oracle数据库带来什么影响。对象
从如今开始,假设DDL并不会自动提交,而是事务中的一部分。递归
那么DDL就要知足READ COMMIT隔离机制,也就是说,用户执行的DDL语句在提交前,其余用户是没法看到的。好比A用户执行CREATE TABLE T的语句,而后对T执行了一些DML。而这时其余会话是没法看到T表的。
那么考虑这样的状况,存在表T,包含两个列,一个ID列,一个CREATED列。
A会话执行了ALTER TABLE T MODIFY CREATED DEFAULT SYSDATE NOT NULL,而后对T表进行了一些插入,可是没有提交。
这时B会话尝试插入T表,若是DDL语句不是事务的一部分,那么B的插入和A会话的插入之间没有冲突,可是如今状况不一样,因为A执行了T表的修改,为CREATED列增长了默认值并设置为NOT NULL,并且这个修改B会话当前是看不到的,由于A并无提交修改。这时若是B会话的插入没有提供CREATED列的值,则插入操做将被锁定。对于B而言,表结构中CREATED列仍然是可空的,所以容许插入CREATED列为空的记录,可是因为A已经设置T的CREATED列非空,且包含默认值,所以B的插入必须被锁定,不然若是A和B所有提交,A会话会发现即便执行了DDL语句,T表中仍然存在CREATED为空的记录。Oracle为了实现DDL能够回滚的功能,且实现多版本读一致性,那么就必须在DDL发生后,将修改的表锁定,避免其余会话的访问形成不一致。这会致使Oracle中出现锁升级的状况,而且严重的影响Oracle的并发性,并且会大大增长死锁产生的概率。
也许有人奇怪SQLSERVER或一些其余的数据库为何能够实现DDL语句的回滚。事实上,前面提到了Oracle也是有能力实现DDL回滚的,只是这会极大的影响Oracle的并发性。要知道,Oracle的锁机制和多版本读一致性使得Oracle的并发性在全部数据库产品中数一数二。显然为了实现DDL的回滚而损失最值得称道的并发性,Oracle认为得不偿失。其余数据库之因此能够实现,是由于这些数据库的锁机制自己就存在必定缺陷,好比大量的锁会占用系统的资源、读写操做互相阻塞、行级锁可能自动升级为表级锁。因为已经存在这些问题,因此实现DDL的回滚并不会在很大程度上使得并发性恶化,由于即便DDL不将行锁升级为表锁,可能其余的因素也会致使这种状况的发生。