在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但似乎没有提到这一点。
在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但似乎没有提到这一点。
执行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;
/
您提供的链接确实覆盖了这一点。 Oracle始终强制执行语句级别的读取一致性 - 这意味着对table1的任何查询都不会返回某些更新的记录,有些则不会。这将是全部或全部,无论隔离级别如何。
谢谢。为了进一步澄清,假设索引4有一个读锁,更新语句是否会等待读锁解除以更新所有5行? – Ted 2012-03-04 06:19:31
@Ted:在Oracle中,读者和作者不会互相阻碍。数据更新时,旧数据会自动保存一段时间(UNDO)。这允许查询在某个时间点读取数据,而不管正在发生什么变化。 – 2012-03-04 06:35:24
@jonearles是的,但是编写者**会互相阻塞(当他们写入相同的行时)。编写者将逐行锁定,这意味着如果所有事务的写入都不以相同顺序完成,则存在潜在的死锁问题。由于UPDATE没有ORDER BY子句,必须使用单独的'SELECT ... ORDER BY ... FOR UPDATE'来保证锁定顺序。 – 2012-03-04 17:18:47
也可能是。
在这种情况下,由于您只更新了5行,因此并行DML将不太可能适用。假设UPDATE
不调用并行DML,行将按顺序更新,尽管行更新的顺序是任意的。 INDEX
1可能是第一个被更新,最后一个被更新,或者它可能在中间被更新。这取决于查询计划。
所有记录将在一次交易中更新为一条记录。 Oracle不保证更新顺序中的任何顺序。
您可以通过您表中的dbms_transaction.local_transaction_id值更新任何字段以进行检查。
从逻辑上讲,它们同时发生。在实践中,他们不这样做,但是你将无法发现差异。如果您执行UPDATE Table 1 SET Index = Index + 1 WHERE INDEXE BETWEEN 1 AND 5',它会变得更有趣。 – 2012-03-04 06:53:58