By Franck Pachot
.
in my previous post I’ve reproduced an issue where some bulk insert into a GTT was generating too much undo. But the real case I encountered was worse: the insert was reading lot of UNDO. And lot of this undo was read from disk.
Jonathan Lewis has pointed me to a possible explanation he has given (here)
I’ve reproduced the testcase from the previous post after setting the database to do flashback logging. Here are the results, comparing tkprof with and without flashback logging, for the 3 kinds of inserts I’ve tested:
count cpu elapsed disk query current rows
------ ----- -------- ----- ------ ------- -----
- row-by-row insert:
FLASHBACK OFF 100000 24.18 25.11 0 1918 314937 100000
FLASHBACK ON 100000 21.50 21.51 2924 1930 317916 100000
- bulk insert:
FLASHBACK OFF 100 0.78 0.78 0 2009 68277 100000
FLASHBACK ON 100 0.88 0.90 1204 2016 69532 100000
- bull insert with APPEND_VALUES
FLASHBACK OFF 100 0.85 1.08 0 6908 7421 100000
FLASHBACK ON 100 1.02 1.68 502 6912 7945 100000
So it’s clear. In FLASHBACK ON we read the same number of blocks, but some of them involve a physical read, where it’s not the case when we don’t do flashback logging.
When Oracle creates new block that overwrite entirely what was stored before into it, then there is no need to read the previous values. The block is directly written in the buffer cache. They are counted as a buffer get, but there is nothing to read – so no disk read at all.
But when database is in FLASHBACK ON, or has a guaranteed restore point, then all overwritten blocks must be logged into the flashback logs because a flashback database has to write them back. So it must be read before being overwritten.
That concern blocks from dropped (or truncated) objects. And that concerns also the expired undo blocks that are reused. And in that case, because they expired after a while (undo_retention) there are good chance that they are not anymore in buffer cache. Consequence is disk reads from UNDO tablespace.
physical reads for flashback new
Here are the statistics of the 3 insert cases from previous blog, where I’ve added the ‘physical reads for flashback new’ one:
NAME VALUE
--------------------------------- ----------
physical reads for flashback new 2924
redo entries 203086
redo size 36492404
undo change vector size 20673192
NAME VALUE
--------------------------------- ----------
physical reads for flashback new 1204
redo entries 31769
redo size 9647772
undo change vector size 6867248
NAME VALUE
--------------------------------- ----------
physical reads for flashback new 506
redo entries 6506
redo size 4105060
undo change vector size 2997752
When we generate 20673192 bytes into 8k blocks, we expect to write at least to 20673192/8192=2524 block. This matches the 2924 ‘physical reads for flashback new’. And it’s exactly the 2924 ‘disk’ reads that we see in the tkprof above.
Measuring the impact
Now back to the initial issue where I had lot of ‘db file sequential read’ on UNDO (file#=2)
Here are some statistics from a 1 hour Statspack:
Top 5 Timed Events Avg %Total
~~~~~~~~~~~~~~~~~~ wait Call
Event Waits Time (s) (ms) Time
----------------------------------------- ------------ ----------- ------ ------
db file sequential read 9,896,083 14,338 1 32.8
Statistic Total per Second per Trans
--------------------------------- ------------------ -------------- ------------
physical reads for flashback new 1,196,359 208.9 14.3
undo change vector size 7,100,240,724 1,240,000.1 84,960.6
flashback log write bytes 16,034,947,072 2,800,375.0 191,872.2
flashback log writes 45,350 7.9 0.5
So from that we know that:
- 1,196,359/9,896,083=12% of ‘db file sequential read’ is for ‘physical reads for flashback new’
- and 16,034,947,072/7,100,240,724= half of flashback logging is for undo
This is the overhead of flashback logging. Reducing the undo generated (see previous block) can be a good recommendation. And besides the flashback logging issue, it will reduce the generated redo as well.