2012-03-04 66 views
7

在Oracle SQL更新语句中,假设更新会影响5行,update语句是否同时或顺序更新所有5行?例如。在Oracle SQL更新语句中,行更新是否同时发生?

UPDATE table1 
set column2 = 'completed' WHERE 
index between 1 AND 5 

在上述语句中,将指数1至5中的序列被更新,即,1,2,3,4,然后5以上,否则会同时发生(1-5一次全部)。

我已经提到Oracle documentation但似乎没有提到这一点。

+0

从逻辑上讲,它们同时发生。在实践中,他们不这样做,但是你将无法发现差异。如果您执行UPDATE Table 1 SET Index = Index + 1 WHERE INDEXE BETWEEN 1 AND 5',它会变得更有趣。 – 2012-03-04 06:53:58

回答

4

执行UPDATE语句后,该语句的效果将对该事务的其余部分(以及如果提交给其他事务)变为可见。 Oracle以什么样的顺序实际执行它,是一个实现细节(同样,SELECT结果的顺序如何不保证,除非你指定ORDER BY的)。


在大多数情况下,这个顺序对客户端无关紧要。一种情况是避免另一个正在更新重叠行的事务造成死锁。 UPDATE将锁定正在更新的行直到事务结束,所以如果两个事务试图锁定相同的行,但顺序不同,则会发生死锁。

避免死锁的标准方法是始终锁定在一个明确定义的顺序中。不幸的是,UPDATE没有ORDER BY子句,但你可以这样做:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
SELECT ... WHERE condition ORDER BY ... FOR UPDATE; 
UPDATE ... WHERE condition; 
COMMIT; 

哪里condition是两者相同的语句。可序列化的隔离级别对于WHERE总是在两个语句中看到相同的一组行是必需的。

或者,在PL/SQL,你可以做这样的事情:

DECLARE 
    CURSOR CUR IS SELECT * FROM YOUR_TABLE WHERE condition ORDER BY ... FOR UPDATE; 
BEGIN 
    FOR LOCKED_ROW IN CUR LOOP 
     UPDATE YOUR_TABLE SET ... WHERE CURRENT OF CUR; 
    END LOOP; 
END; 
/
2

您提供的链接确实覆盖了这一点。 Oracle始终强制执行语句级别的读取一致性 - 这意味着对table1的任何查询都不会返回某些更新的记录,有些则不会。这将是全部或全部,无论隔离级别如何。

+0

谢谢。为了进一步澄清,假设索引4有一个读锁,更新语句是否会等待读锁解除以更新所有5行? – Ted 2012-03-04 06:19:31

+0

@Ted:在Oracle中,读者和作者不会互相阻碍。数据更新时,旧数据会自动保存一段时间(UNDO)。这允许查询在某个时间点读取数据,而不管正在发生什么变化。 – 2012-03-04 06:35:24

+0

@jonearles是的,但是编写者**会互相阻塞(当他们写入相同的行时)。编写者将逐行锁定,这意味着如果所有事务的写入都不以相同顺序完成,则存在潜在的死锁问题。由于UPDATE没有ORDER BY子句,必须使用单独的'SELECT ... ORDER BY ... FOR UPDATE'来保证锁定顺序。 – 2012-03-04 17:18:47

4

也可能是。

在这种情况下,由于您只更新了5行,因此并行DML将不太可能适用。假设UPDATE不调用并行DML,行将按顺序更新,尽管行更新的顺序是任意的。 INDEX 1可能是第一个被更新,最后一个被更新,或者它可能在中间被更新。这取决于查询计划。

2

UPDATE,DELETE和INSERT没有定义的顺序。从概念上讲,他们适用于一套,一次完成。实际上,不要依赖任何你可能观察到的序列 - 它是一个可以改变的实现细节,而只是因为现实世界妨碍了理论而发生。

+0

谢谢!我推断更新是基于集合的方式完成的,即更新将在执行更新语句之前等待所有行可用。 – Ted 2012-03-04 06:21:22

+0

@Ted:Oracle会执行块级锁定,但在更新开始时不必解锁所有行。 – jmoreno 2012-03-04 07:44:15

0

所有记录将在一次交易中更新为一条记录。 Oracle不保证更新顺序中的任何顺序。

您可以通过您表中的dbms_transaction.local_transaction_id值更新任何字段以进行检查。