(1)-Oracle Write Consistency and ORA-00600: [13030], [20]
(2)-Oracle Write Consistency and ORA-30926
We will discuss Oracle Write Consistency and different error messages in two Blogs.
This Blog will make one test to demonstrate Write Consistency and error ORA-00600: [13030], [20].
Next Blog will show
Write Consistency and ORA-30926: "unable to get a stable set of rows in the source tables".
We will show that error message depends on column declaration:
for column "not null", it is ORA-00600: [13030], [20]
for column "null", it is ORA-30926: "unable to get a stable set of rows in the source tables"
Note: Tested in Oracle 19.13, 19.7, 18.9, 12.1
1. Test Setup
We create a simple table with two columns, and insert two rows:
drop table test_tab;
create table test_tab (id number, txt varchar2(1) not null, constraint test_tab_pk primary key (id));
-- ORA-30926: unable to get a stable set of rows
--create table test_tab (id number, txt varchar2(1), constraint test_tab_pk primary key (id));
insert into test_tab values (1, 'A');
insert into test_tab values (2, 'A');
commit;
SQL> select * from test_tab;
ID TXT
--- ----
1 A
2 A
Then create a non deterministic function (non_deterministic_fun) in a Plsql package.
The function toggles its return value as 0 or 1 in successive call for the given input after sleeping the specified seconds.
create or replace package test_pkg as
b_1_cnt number := 0;
b_2_cnt number := 0;
function non_deterministic_fun(p_id number, p_sleep number := 10) return number;
procedure set_cnt (p_1_cnt number, p_2_cnt number);
procedure prt_tx_locks;
end;
/
create or replace package body test_pkg as
function non_deterministic_fun(p_id number, p_sleep number := 10) return number as
l_ret number;
l_cnt_str varchar2(20);
begin
case p_id
when 1 then
b_1_cnt := b_1_cnt + 1;
l_ret := mod(b_1_cnt, 2);
l_cnt_str := ': b_1_cnt='||b_1_cnt;
when 2 then
b_2_cnt := b_2_cnt + 1;
l_cnt_str := ': b_2_cnt='||b_2_cnt;
l_ret := mod(b_2_cnt, 2);
end case;
dbms_lock.sleep(p_sleep); --dbms_session.sleep(p_sleep); -- Oracle 19c
dbms_output.put_line('At '||localtimestamp ||l_cnt_str||', non_deterministic_fun('||p_id||', '||p_sleep||')='||l_ret);
prt_tx_locks; -- Print TX locks
return l_ret;
end;
procedure set_cnt (p_1_cnt number, p_2_cnt number) as
begin
b_1_cnt := p_1_cnt;
b_2_cnt := p_2_cnt;
dbms_output.put_line('At '||localtimestamp ||': Reset Package Variables: b_1_cnt='||b_1_cnt||', b_2_cnt='||b_2_cnt);
dbms_output.put_line('');
end;
procedure prt_tx_locks as
l_spaces varchar2(6) := ' ';
begin
dbms_output.put_line('');
dbms_output.put_line(l_spaces||'|------------------------------------------------------|');
dbms_output.put_line(l_spaces||'|SID ID1 ID2 LMODE REQUEST CTIME BLOCK|');
dbms_output.put_line(l_spaces||'|------ ------- ------- ------- ------- ------- -------|');
for c in (select * from v$lock where type='TX' order by sid, type)
loop
dbms_output.put_line(l_spaces||'|'||rpad(c.SID, 6)||lpad(c.ID1, 8)||lpad(c.ID2, 8)||lpad(c.LMODE, 8)||
lpad(c.REQUEST, 8)||lpad(c.CTIME, 8)||lpad(c.BLOCK, 8)||'|');
end loop;
dbms_output.put_line(l_spaces||'|------------------------------------------------------|');
dbms_output.put_line('');
end;
end;
/
2. Test Run
We open two Sqlplus sessions: SID-1 and SID-2.
At T1, SID-1 updates txt from 'A' to 'B' for id=2.
--========== 1. SID-1@T1 ==========--
begin
update test_tab set txt = 'A';
commit;
-- block id=2 update
update test_tab
set txt = 'B'
where txt = 'A'
and id = 2;
dbms_output.put_line('At '||localtimestamp ||': update id=2 from A to B');
end;
/
---- Output ----
At 16:12:11: update id=2 from A to B
At T2, SID-2 updates txt from 'A' to 'B' with filter condition: "test_pkg.non_deterministic_fun(id, 10) > 0",
which sleeps 10 seconds before return. Its output toggles as 0 or 1 in successive call for the given id.
We also use DML UTS (Unified Tracing Service) described in Blog:
Write consistency and DML restart (Mahmoud Hatem)
to monitor Oracle three phases of update restart.
--========== 2. SID-2@T2 ==========--
alter session set tracefile_identifier = 'NotNull_Error_1';
alter session set events 'trace[DML] disk=high ';
exec dbms_monitor.session_trace_enable;
--ALTER SESSION SET "_fix_control"='30681521:0';
begin
test_pkg.set_cnt(0, 0); -- reset package state
update test_tab -- update /*+ RETRY_ON_ROW_CHANGE */ test_tab -- hint has no effect
set txt = 'B'
where txt = 'A'
and test_pkg.non_deterministic_fun(id, 10) > 0;
end;
/
---- Output ----
At 16:12:50: Reset Package Variables: b_1_cnt=0, b_2_cnt=0
At 16:13:00: b_1_cnt=1, non_deterministic_fun(1, 10)=1
At 16:13:10: b_2_cnt=1, non_deterministic_fun(2, 10)=1
At 16:14:12: b_1_cnt=2, non_deterministic_fun(1, 10)=0
At 16:14:22: b_1_cnt=3, non_deterministic_fun(1, 10)=1
ORA-00600: internal error code, arguments: [13030], [20], [], [], [], [], [], [], [], [], [], []
Elapsed: 00:01:45.30
At T3, SID-1 sleeps 30 seconds and commits its T1 update.
Sleeps another 5 seconds.
Then updates txt from 'A' to 'B' for id=1 and commit.
--========== 3. SID-1@T3 ==========--
begin
dbms_output.put_line('At '||localtimestamp ||': wait id=2 update for 30 seconds');
test_pkg.prt_tx_locks;
dbms_lock.sleep(30);
commit;
dbms_output.put_line('At '||localtimestamp ||': commit id=2 update. Then wait 5 seconds');
dbms_lock.sleep(5); -- This wait to de-block id=2 is critical, otherwise no error
update test_tab
set txt = 'B'
where txt = 'A'
and id = 1;
test_pkg.prt_tx_locks;
commit;
dbms_output.put_line('At '||localtimestamp ||': update id=1 from A to B, and commit');
end;
/
---- Output ----
At 16:13:32: wait id=2 update for 30 seconds
At 16:14:02: commit id=2 update. Then wait 5 seconds
At 16:14:07: update id=1 from A to B, and commit
Elapsed: 00:00:35.04
From test output, we can see the update sequence:
At 16:12:11: SID-1 update id=2 from A to B.
At 16:12:50: SID-2 start running. get into "phase=NOT LOCKED". sleep 10 seconds.
At 16:13:00: SID-2 update id=1 because non_deterministic_fun(1, 10)=1. sleep 10 seconds.
At 16:13:10: SID-2 update id=2, but SID-1 does not commit "id=2 update", it is blocked by "TX" lock for 52 seconds (ela= 52217121).
At 16:14:02: SID-1 commit "id=2 update". SID-2 is unlocked.
SID-2 restart update, get into "phase=LOCK" with "SELECT FOR UPDATE". sleep 10 seconds.
At 16:14:07: SID-1 update id=1 from A to B, and commit.
At 16:14:12: SID-2 get into "phase=NOT LOCKED". id=1 check non_deterministic_fun(1, 10)=0. sleep 10 seconds.
At 16:14:22: SID-2 id=1 check non_deterministic_fun(1, 10)=1.
SID-2 raise ORA-00600: internal error code, arguments: [13030], [20]
Here SID-2 DML UTS tracing file (only related lines extracted).
===================== *** 16:12:50
PARSING IN CURSOR tim=12445563522721 hv=3131174352 ad='c080e660' sqlid='6jabvd6xa3vfh'
UPDATE TEST_TAB SET TXT = 'B' WHERE TXT = 'A' AND TEST_PKG.NON_DETERMINISTIC_FUN(ID, 10) > 0
updThreePhaseExe: objn=3122646 phase=NOT LOCKED
updaul: phase is NOT LOCKED snap oldsnap env: (scn: 0x000009185dcf3734 xid: 0x0000.000.00000000 uba:
===================== *** 16:13:00
WAIT: nam='PL/SQL lock timer' ela= 10000786 tim=12445573526055
updrow: objn=3122646 phase=NOT LOCKED
updrow: kauupd objn:3122646 rowid 002fa5d6.000c9786.0 code 0
===================== *** 16:13:10
WAIT: nam='PL/SQL lock timer' ela= 10000287 tim=12445583549063
updrow: objn=3122646 phase=NOT LOCKED
===================== *** 16:14:02
WAIT: nam='enq: TX - row lock contention' ela= 52217121 name|mode=1415053318 usn<<16 | slot=8323077 sequence=80529 obj#=3122646 tim=12445635782319
dmlTrace:file:line (kdu.c:3505) cmpf 20 rowcol 1 piececol 1
updrow: kauupd objn:3122646 rowid 002fa5d6.000c9786.1 code 20
updThreePhaseExe: objn=3122646 phase=LOCK
===================== *** 16:14:12
WAIT: nam='PL/SQL lock timer' ela= 10000133 tim=12445645783076
updThreePhaseExe: objn=3122646 phase=ALL LOCKED
===================== *** 16:14:22
WAIT: nam='PL/SQL lock timer' ela= 10000583 tim=12445655800069
updrow: objn=3122646 phase=ALL LOCKED
Block header dump: 0x000c9786
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x007f.005.00013a91 0x00c026bf.2019.0f --U- 1 fsc 0x0000.5dcf3755
0x02 0x0075.010.00011cca 0x00c01798.1e21.21 --U- 1 fsc 0x0000.5dcf375a
===============
block_row_dump:
tab 0, row 0, @0x1f90
tl: 8 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 2] c1 02
col 1: [ 1] 42
tab 0, row 1, @0x1f88
tl: 8 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 03
col 1: [ 1] 42
kflag
[0] CMPCOL
cmpp (2) c1 02
[1] CMPCOL UPDCOL
cmpp (1) 41
updp (1) 42
updrow: CR error table 0 - rowid: 002fa5d6.000c9786.0 code 20
dmlsrvRetryLogDump: seq:code:error:pass:hash:rowcol:piececol:currentLength:currentFlags:CRLength:CRFlags:rid:scn
dmlsrvRetryLogDump: 0:20:0:1:2139311695:1:1:1:0:1:0:002fa5d6.000c9786.1:0x000009185dcf3734
dmlsrvRetryLogDump: 1:20:0:3:2139311695:1:1:1:0:1:0:002fa5d6.000c9786.0:0x000009185dcf3757
=====================
ORA-00600: internal error code, arguments: [13030], [20], [], [], [], [], [], [], [], [], [], []
Above trace file records all the details of ThreePhase updates:
===================== *** 16:12:50
updThreePhaseExe: objn=3122646 phase=NOT LOCKED
===================== *** 16:14:02
updThreePhaseExe: objn=3122646 phase=LOCK
===================== *** 16:14:12
updThreePhaseExe: objn=3122646 phase=ALL LOCKED
At 16:14:02, SID-1 committed the updated of id=2 (rowid 002fa5d6.000c9786.1),
SID-2 finished "TX" wait after 52 seconds (ela= 52217121).
dmlTrace shows code 20 error: "rowid 002fa5d6.000c9786.1 code 20".
(maybe "line (kdu.c:3505) cmpf 20" is interpreted as "code 20" or [20] in error message).
"phase=LOCK" signifies the update restart.
===================== *** 16:14:02
WAIT: nam='enq: TX - row lock contention' ela= 52217121 name|mode=1415053318 usn<<16 | slot=8323077 sequence=80529 obj#=3122646 tim=12445635782319
dmlTrace:file:line (kdu.c:3505) cmpf 20 rowcol 1 piececol 1
updrow: kauupd objn:3122646 rowid 002fa5d6.000c9786.1 code 20
updThreePhaseExe: objn=3122646 phase=LOCK
At 16:14:22, Itl section list two "fast commit" entries.
Itl 0x01 (lb: 0x1) updated id=2 ("c1 03"),
Itl 0x02 (lb: 0x2) updated id=1 ("c1 02").
If we look the TX v$lock printout ("ID1 ID2" in test_pkg.prt_tx_locks, not showed in this Blog), we can match both Xid
(0x007f.005.00013a91 = 127.5.80529, 0x0075.010.00011cca=117.16.72906).
block_row_dump section shows that both rows have txt = 'B' ("col 1: [ 1] 42").
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x007f.005.00013a91 0x00c026bf.2019.0f --U- 1 fsc 0x0000.5dcf3755
0x02 0x0075.010.00011cca 0x00c01798.1e21.21 --U- 1 fsc 0x0000.5dcf375a
===============
block_row_dump:
tab 0, row 0, @0x1f90
tl: 8 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 2] c1 02 -- 1
col 1: [ 1] 42 -- 'B'
tab 0, row 1, @0x1f88
tl: 8 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 03 -- 2
col 1: [ 1] 42 -- 'B'
kflag section shows that we want to update id = 1 ("c1 02") from 'A' ("cmpp (1) 41") to 'B' ("updp (1) 42")
for "rowid: 002fa5d6.000c9786.0" (row 0), but failed with "code 20".
kflag
[0] CMPCOL
cmpp (2) c1 02 -- 1
[1] CMPCOL UPDCOL
cmpp (1) 41 -- 'A'
updp (1) 42 -- 'B'
updrow: CR error table 0 - rowid: 002fa5d6.000c9786.0 code 20
dmlsrvRetryLogDump section shows two errors with code=20.
We got code=20 in "pass=1" ( "phase=NOT LOCKED") for id=2 ("rid=002fa5d6.000c9786.1"),
and got code=20 in "pass=3" ( "phase=ALL LOCKED") for id=1 ("rid=002fa5d6.000c9786.0")
dmlsrvRetryLogDump: seq:code:error:pass:hash:rowcol:piececol:currentLength:currentFlags:CRLength:CRFlags:rid:scn
dmlsrvRetryLogDump: 0:20:0:1:2139311695:1:1:1:0:1:0:002fa5d6.000c9786.1:0x000009185dcf3734
dmlsrvRetryLogDump: 1:20:0:3:2139311695:1:1:1:0:1:0:002fa5d6.000c9786.0:0x000009185dcf3757
In the above update sequence, SID-1 makes a second update:
At 16:14:07 update id=1 from A to B, and commit
It is not clear if SID-2 has to perform a second re-start
because it is between SID-2 16:14:02 ("phase=LOCK") and 16:14:12 ("phase=NOT LOCKED").
Probably that is the code path which caused ORA-00600.
In the above test, if we remove this second update in SID-1@T3 as follows,
and there is no more ORA-00600 because no second re-start is triggered.
--========== 3. SID-1@T3 ==========--
begin
dbms_output.put_line('At '||localtimestamp ||': wait id=2 update for 30 seconds');
test_pkg.prt_tx_locks;
dbms_lock.sleep(30);
commit;
end;
/
Here the incident file, which shows the Call Stack (only partially extracted):
ORA-00600: internal error code, arguments: [13030], [20], [], [], [], [], [], [], [], [], [], []
*** 2022-04-06T16:14:22.450668+02:00
----- Current SQL Statement for this session (sql_id=6jabvd6xa3vfh) -----
UPDATE TEST_TAB SET TXT = 'B' WHERE TXT = 'A' AND TEST_PKG.NON_DETERMINISTIC_FUN(ID, 10) > 0
----- Call Stack Trace -----
FRAME [13] (ksesic1()+185 -> kgesiv())
FRAME [14] (updrow()+5781 -> ksesic1())
FRAME [15] (qerupUpdRow()+671 -> updrow())
FRAME [16] (qerupRopRowsets()+259 -> qerupUpdRow())
FRAME [17] (qerstRowP()+737 -> qerupRopRowsets())
FRAME [18] (kdstf110110100001000km()+1884 -> qerstRowP())
FRAME [19] (kdsttgr()+2208 -> kdstf110110100001000km())
FRAME [20] (qertbFetch()+1090 -> kdsttgr())
FRAME [21] (qerstFetch()+449 -> qertbFetch())
FRAME [22] (qerupFetch()+520 -> qerstFetch())
FRAME [23] (qerstFetch()+910 -> qerupFetch())
FRAME [24] (updaul()+1416 -> qerstFetch())
FRAME [25] (updThreePhaseExe()+6101 -> updaul())
FRAME [26] (updexe()+443 -> updThreePhaseExe())
FRAME [27] (opiexe()+11799 -> updexe())
FRAME [28] (opipls()+2427 -> opiexe())
In the above test, if we change row update sequence as follows:
for SID-1@T1, we update "id = 1" instead of "id = 2"
for SID-1@T3, we update "id = 2" instead of "id = 1"
there is no more error, and SID-2 DML UTS tracing file (only related lines extracted) looks like
(in SID-2, no rows updated, no Itl entry, no transaction created):
*** 17:44:51
updThreePhaseExe: objn=3122646 phase=NOT LOCKED
updaul: phase is NOT LOCKED snap oldsnap env:
*** 17:45:01
WAIT #140344716597752: nam='PL/SQL lock timer' ela= 10000544 duration=0 p2=0 p3=0 obj#=-1 tim=13376295440067
updrow: objn=3122646 phase=NOT LOCKED
*** 17:45:56
WAIT #140344716597752: nam='enq: TX - row lock contention' ela= 54748944 name|mode=1415053318 usn<<16 | slot=7602177 sequence=77639 obj#=3122646 tim=13376350189277
dmlTrace:file:line (kdu.c:3505) cmpf 20 rowcol 1 piececol 1
updrow: kauupd objn:3122646 table:0 rowMigrated:FALSE rowid 002fa5d6.000c9786.0 code 20
updThreePhaseExe: objn=3122646 phase=LOCK
updaul: phase is LOCK snap oldsnap env:
*** 17:46:06
WAIT #140344716597752: nam='PL/SQL lock timer' ela= 10000260 duration=0 p2=0 p3=0 obj#=-1 tim=13376360190078
updrow: objn=3122646 phase=LOCK
dmlTrace:file:line (kdd.c:3642) cmpf 17 rowcol 1 piececol 1
updrow: kddlkr objn 3122646 table 0 rowid 002fa5d6.000c9786.1 code 17
updThreePhaseExe:objn=3122646 pass=1 stat=2 err=17
updThreePhaseExe:began locking pass 2
updaul: phase is LOCK snap oldsnap env:
updThreePhaseExe: objn=3122646 phase=ALL LOCKED
updaul: phase is ALL LOCKED snap oldsnap env:
3. Related Work
Oracle MOS Ora-00600 [13030], [20] During Update Statement Using V$ tables (Doc ID 1400439.1) wrote:
For updates we use a 3 pass algorithm which relies on consistent read. If the first pass does not succeed
then we use a CR scan and lock the rows returned, then reset the row source and use a further CR scan at the same snapshot SCN
to update those locked rows. The V$ view in the WHERE clause does not support CR and so each scan using the same snapshot SCN
may see different data depending on the content of V$SESSION at the scan time which completely breaks the update algorithm.
The errors you see (ORA-600 [13030]) indicate:
[1] - the row to be updated has changed values in comparison columns
[2] - the row to be updated does not exist
These are the sorts of error you can get if the separate scans at the same snapshot SCN return different data, as can occur with a V$ view involved.
Book:
Expert Oracle Database Architecture (Thomas Kyte, Darl Kuhn, 3rd Edition)
explained update restart and demonstrated it with triggers.
Page 270 wrote:
But to continue on with the "but what happens if..." train of thought, what happens if, after
restarting the update and going into SELECT FOR UPDATE mode (which has the same read-consistent and
read current block gets going on as an update does), a row that was Y=5 when you started the SELECT FOR
UPDATE is found to be Y=11 when you go to get the current version of it? That SELECT FOR UDPDATE will
restart and the cycle begins again.
This seems talking about a second restart after first restart.
The above test showed ORA-00600: [13030], [20] in such second restart,
and "cycle begins again" abnormally terminated (session is not disconnected).
So it is not clear if
"but what happens if..." has ever been exercised.
For the update statement in the second session of Book Page 271,
if we add a MONITOR hint and make a Sql trace:
(see Video:
Oracle SQL Monitoring and Write Consistency Demo (Tanel Poder))
alter session set events '10046 trace name context forever, level 12';
-- with /*+ MONITOR */
update /*+ MONITOR */ t set x = x+1 where x > 0;
alter session set events '10046 trace name context off';
Here MONITOR report and Sql trace:
select sys.dbms_sqltune.report_sql_monitor('canctsv349dww', report_level=>'all' , type=>'TEXT') from dual;
------------------------------
update /*+ MONITOR */ t set x = x+1 where x > 0
SQL Plan Monitoring Details (Plan Hash Value=931696821)
=============================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (%) | (# samples) |
=============================================================================================================================================
| 0 | UPDATE STATEMENT | | | | 1 | +13 | 3 | 0 | | |
| 1 | UPDATE | T | | | 14 | +0 | 3 | 0 | 100.00 | enq: TX - row lock contention (13) |
| 2 | TABLE ACCESS FULL | T | 4 | 2 | 11 | +3 | 3 | 3 | | |
=============================================================================================================================================
********************************************************************************
SQL ID: canctsv349dww Plan Hash: 931696821
update /*+ MONITOR */ t set x = x+1 where x > 0
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.00 12.61 0 21 13 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 12.61 0 22 13 1
Rows Row Source Operation
---- ---------------------------------------------------
0 UPDATE T (cr=21 pr=0 pw=0 time=12612642 us starts=3)
3 TABLE ACCESS FULL T (cr=20 pr=0 pw=0 time=222 us starts=3 cost=2 size=104 card=4)
********************************************************************************
MONITOR report shows that "TABLE ACCESS FULL" has Execs=3 and Rows=3
and xplan shows that "TABLE ACCESS FULL" has Rows=3 and starts=3,
although only one single row is updated (without update restart, all above numbers are 1).
All those number 3 exactly signify "updThreePhaseExe".
By the way, an erratum of Foreign Key on Nested Table (maybe the only real one) was reported for 1st Edition of
Book: Book Expert Oracle Database Architecture.
It was once accepted and published, but now it cannot find any more.
In Oracle 19.13, repeated the same test from Blog: Foreign Key on Nested Table
Foreign Key on Nested Table can still successfully created (in Oracle 19.13, type has to be created as NONEDITIONABLE).
But in Page 410 of 3rd Edition, we can still read:
This will simply not work. Nested tables do not support referential integrity constraints, as they
cannot reference any other tableóeven themselves. So, weíll just skip that requirement for this
demonstration (something you cannot do in real life!).
And error message (Page 409) seems disapproved:
ORA-30730: referential constraint not allowed on nested table column
Blog:
Oracle write consistency bug and multi-thread de-queuing (Franck Pachot)
showed an update restart bug with nested subquery and used flashback version query to list all versions of the rows.
It also mentioned hint RETRY_ON_ROW_CHANGE, which has no effect on the test of this Blog.
Oracle MOS Bug 33470254 - UPDATE FAILS WITH ORA-00600 [13030], [20] (Doc ID 33470254.8) provided a Workaround:
"_fix_control"= '30681521:0' (Versions affected, 19.11, 19.13, 19.14)
which seems related to subqueries (see V$SYSTEM_FIX_CONTROL.DESCRIPTION).
Our 19.13 test DB is set with this _fix_control, but it has no effect.
select bugno, value, description from v$system_fix_control where bugno=30681521;
BUGNO VALUE DESCRIPTION
-------- ----- ----------------------------------------------------------------
30681521 0 enable unnesting of subqueries in set clause of update statement
Video:
Oracle SQL Monitoring and Write Consistency Demo (Tanel Poder)
demonstrated restart by a big table update on Oracle 18.3, and detected them by V$SQL_PLAN_MONITOR.STARTS and Sql Trace.
In the demo, SQL Monitoring also shows that Actual Rows with restart is at least double than without restart.
So Actual Rows (V$SQL_PLAN_MONITOR.OUTPUT_ROWS) could be also an indicator of update restart besides V$SQL_PLAN_MONITOR.STARTS (str).
The demo contains two tests, one at Wed Sep 5, 2018 10:42:47 AM, another at Wed Sep 5, 2018 3:51:30 PM.
First test involved 9 rows (9 + 8 + 8 = 25 rows in all ThreePhase),
second touched 10 rows (10 + 9 + 9 = 28 rows in all ThreePhase)
Blog:
Write consistency and DML restart (Mahmoud Hatem)
explored DML UTS (Unified Tracing Service) tracing to investigate update restart,
which revealed the very details of updThreePhaseExe.
(In its test, without update of Session 2, trace file shows str=3 instead of str=4).
A series of 3 Blogs:
That Old Restart Problem Strikes Back: Setting the Stage
That Old Restart Problem Strikes Back: Getting What You Pay for
That Old Restart Problem Strikes Back: Triggers to the Rescue
demonstrated the single session update restart without any other interfering sessions.
It also uses:
alter session set events 'trace[dml]:sql_trace wait=true';
to reveal internal handled error ORA-01551.
The first Blog shows that such update restart is only observed in non-partitioned table due to "updrowFastPath".
The second Blog points out that there is such update restart in partitioned table due to "updrow".
The third Blog shows that such update restart disappears in non-partitioned table when there is a after trigger due to "updrow".
Blog:
Update restarts
reveals various Oracle stats in update restart.