Oracle 11.2.0.4 on OEL 6.5
Our app admin run some update script from app vendor,
and this script has been running for several hours and no one know when it will end. Also database now generates lots of archivelogs.
I started sql trace for 15 minutes and found that there is almost the only query.
INSERT INTO house_t
VALUES
(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15, :16,
:17, :18, :19, :20, :21, :22, :23)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 70 0.00 0.00 0 0 0 0
Execute 71 23.86 633.03 83564 41375 4597750 355735
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 141 23.87 633.03 83564 41375 4597750 355735
Why one simple insert needs to use this huge amount of blocks in current mode 64757=4597750/71 ???
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 103
Number of plan statistics captured: 3
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 LOAD TABLE CONVENTIONAL (cr=584 pr=1443 pw=0 time=11388214 us)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net more data from client 9523 0.00 0.08
db file sequential read 82252 0.60 603.94
SQL*Net message to client 70 0.00 0.00
SQL*Net message from client 70 0.00 0.15
log file switch completion 4 0.08 0.18
undo segment extension 4 0.00 0.01
log file sync 1 0.00 0.00
Table has simple structure:
SQL> desc house_t
Name Null? Type
-------------------- -------- --------------
POSTALCODE VARCHAR2(6)
IFNSFL VARCHAR2(4)
TERRIFNSFL VARCHAR2(4)
IFNSUL VARCHAR2(4)
TERRIFNSUL VARCHAR2(4)
OKATO VARCHAR2(11)
OKTMO VARCHAR2(11)
UPDATEDATE DATE
HOUSENUM VARCHAR2(20)
ESTSTATUS NUMBER(5)
BUILDNUM VARCHAR2(10)
STRUCNUM VARCHAR2(10)
STRSTATUS NUMBER(5)
HOUSEID VARCHAR2(36)
HOUSEGUID VARCHAR2(36)
AOGUID VARCHAR2(36)
STARTDATE DATE
ENDDATE DATE
STATSTATUS NUMBER(5)
NORMDOC VARCHAR2(36)
COUNTER NUMBER(10)
CADNUM VARCHAR2(100)
DIVTYPE NUMBER(5)
There are no triggers on this table, no mviews, no defined fga policies, no fgac policies.
Also table has 3 indexes
CREATE UNIQUE INDEX HOUSE_T_IDX0 ON HOUSE_T(HOUSEID);
CREATE INDEX HOUSE_T_IDX1 ON HOUSE_T (T_HOUSEGUID);
CREATE INDEX HOUSE_T_IDX2 ON HOUSE_T (T_AOGUID);
Raw trace file is full of 'db file sequential read' waits on this 3 indexes and undo blocks.
Table now has about 50M records, size is about 12Gb.
Indexes are about 3-4GB and have blevel=3 in dba_indexes.
I expect that this insert statement can take 20-30 blocks to run, but why thousands ?
Best Answer
Steps to reproduce:
Sample data:
Now to simulate your script:
And the tkprof output:
And an enormous amount of
leaf node splits
:1) I am using an SSD here, that is why my demo took much less time, because of the much lower disk response time. You should look at the amount of
current
blocks, not the time spent on this.2) I am inserting data in randomized order, this causes
leaf block splits
.leaf node 90-10 splits
are caused by inserting data to the rightmost part of the index, in a sequentially increasing order.leaf node 90-10 splits
can be simply done by adding new index blocks to the "rightmost" part of the index, then copy the highest value into them. Sometimes it is unofficially referred as a99-1
split instead of90-10
.leaf block splits
means adding new blocks in the "middle" of the index, copying and rearranging data in several blocks, this is much more work.3) Performance-wise I find it very a bad idea to use GUIDs as identifiers. They consume multiple times more storage space compared to simple
NUMBER
identifiers.This is the same, but with NUMBER types:
Also: Limitations of the Oracle Cost Based Optimizer (Doc ID 212809.1)
This has caused some seriously incorrect cardinality misestimates with histograms on GUID columns.
This is how this behaves when values are inserted in an increasing order (removed
order by dbms_random.value
):As you can see, it is less than 1 current block per row.