....
But what about performance? Would these big numbers be slower to use in queries (lookups by primary key value or filters when they are used as foreign keys) than the smaller numbers? Carsten mentions that the buffer cache gets filled up/exhausted faster when the key values are larger? And indexing would suffer from more fragmented values? ....
Ofcourse 40% more CPU than sequence based key columns.
demo@ORA12C> create table t1(x number constraint t1_pk primary key,
2 data varchar2(100) );
Table created.
demo@ORA12C>
demo@ORA12C> create table t2(x number constraint t2_pk primary key,
2 data varchar2(100) );
Table created.
demo@ORA12C> create sequence s1 cache 1000;
Sequence created.
demo@ORA12C>
demo@ORA12C> variable n number
demo@ORA12C> exec :n := 100000;
PL/SQL procedure successfully completed.
demo@ORA12C>
demo@ORA12C> exec runstats_pkg.rs_start;
PL/SQL procedure successfully completed.
demo@ORA12C> begin
2 for i in 1..:n
3 loop
4 insert into t1(x,data)
5 values( to_number(sys_guid(),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') ,'x');
6 commit;
7 end loop;
8 end;
9 /
PL/SQL procedure successfully completed.
demo@ORA12C> exec runstats_pkg.rs_middle;
PL/SQL procedure successfully completed.
demo@ORA12C> begin
2 for i in 1..:n
3 loop
4 insert into t2(x,data)
5 values( s1.nextval ,'x');
6 commit;
7 end loop;
8 end;
9 /
PL/SQL procedure successfully completed.
demo@ORA12C> exec runstats_pkg.rs_stop(1000);
Run1 ran in 2662 hsecs and CPU time in 1238 hsecs
Run2 ran in 1878 hsecs and CPU time in 789 hsecs
run 1 ran in 141.75% of the time
Name Run1 Run2 Diff
STAT...commit cleanouts 201,623 200,483 -1,140
STAT...commit cleanouts succes 201,619 200,478 -1,141
STAT...deferred (CURRENT) bloc 148,831 150,005 1,174
STAT...immediate (CURRENT) blo 1,625 373 -1,252
STAT...calls to kcmgcs 3,038 1,650 -1,388
STAT...db block gets from cach 102,947 101,434 -1,513
STAT...physical reads for flas 5,239 3,716 -1,523
STAT...physical read total IO 5,249 3,725 -1,524
STAT...non-idle wait count 5,285 3,761 -1,524
STAT...physical read IO reques 5,242 3,718 -1,524
STAT...physical reads cache 5,242 3,718 -1,524
STAT...physical reads 5,242 3,718 -1,524
STAT...free buffer requested 5,275 3,742 -1,533
LATCH.undo global data 306,870 304,750 -2,120
LATCH.object queue header oper 22,940 20,131 -2,809
STAT...redo entries 309,693 303,835 -5,858
STAT...messages sent 28,374 19,988 -8,386
LATCH.lgwr LWN SCN 28,393 20,001 -8,392
LATCH.Consistent RBA 28,352 19,783 -8,569
STAT...db block changes 615,111 605,992 -9,119
STAT...db block gets 522,259 512,902 -9,357
STAT...db block gets from cach 522,259 512,902 -9,357
STAT...session logical reads 525,393 515,079 -10,314
LATCH.messages 62,757 42,792 -19,965
LATCH.redo allocation 85,648 60,145 -25,503
LATCH.redo writing 85,176 59,504 -25,672
LATCH.cache buffers chains 2,129,928 2,094,408 -35,520
STAT...session uga memory max 123,512 65,488 -58,024
STAT...KTFB alloc time (ms) 68,898 3,345 -65,553
STAT...calls to get snapshot s 100,663 200,494 99,831
STAT...session pga memory max 0 131,072 131,072
STAT...session pga memory -65,536 196,608 262,144
LATCH.sequence cache 0 300,200 300,200
STAT...file io wait time 13,106,639 8,929,040 -4,177,599
STAT...undo change vector size 28,674,336 23,982,244 -4,692,092
STAT...KTFB alloc space (block 44,040,192 32,505,856 -11,534,336
STAT...redo size 99,250,308 87,146,032 -12,104,276
STAT...physical read bytes 42,942,464 30,457,856 -12,484,608
STAT...physical read total byt 43,057,152 30,572,544 -12,484,608
STAT...cell physical IO interc 43,057,152 30,572,544 -12,484,608
STAT...logical read bytes from######################## -84,492,288
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
3,718,603 3,886,768 168,165 95.67%
PL/SQL procedure successfully completed.
demo@ORA12C>
while sequence based keys lead to appealing clustering factors.
demo@ORA12C> exec dbms_stats.gather_table_stats(user,'T1');
PL/SQL procedure successfully completed.
demo@ORA12C> exec dbms_stats.gather_table_stats(user,'T2');
PL/SQL procedure successfully completed.
demo@ORA12C> select index_name, clustering_factor,t.num_rows,t.blocks
2 from user_indexes i,
3 user_tables t
4 where i.table_name in ('T1','T2')
5 and i.table_name = t.table_name
6 order by index_name ;
INDEX_NAME CLUSTERING_FACTOR NUM_ROWS BLOCKS
---------- ----------------- ---------- ----------
T1_PK 99745 100000 496
T2_PK 164 100000 244
2 rows selected.
90-10% leaf block split up for Sequences and 50-50% split up for guid based key columns.
demo@ORA12C> analyze index t1_pk validate structure;
Index analyzed.
demo@ORA12C> select name, blocks,lf_blks,btree_space,used_space,pct_used from index_stats;
NAME BLOCKS LF_BLKS BTREE_SPACE USED_SPACE PCT_USED
------------- ---------- ---------- ----------- ---------- ----------
T1_PK 640 541 4336032 3175082 74
1 row selected.
demo@ORA12C>
demo@ORA12C> analyze index t2_pk validate structure;
Index analyzed.
demo@ORA12C> select name, blocks,lf_blks,btree_space,used_space,pct_used from index_stats;
NAME BLOCKS LF_BLKS BTREE_SPACE USED_SPACE PCT_USED
------------ ---------- ---------- ----------- ---------- ----------
T2_PK 256 187 1504032 1490919 100
1 row selected.
Range scans will be affected due to clustering factors.
demo@ORA12C> column min_x new_val min_x
demo@ORA12C> column max_x new_val max_x
demo@ORA12C>
demo@ORA12C> select min(x) min_x,max(x) max_x
2 from ( select x from t1
3 order by x
4 fetch first 100 row only );
MIN_X MAX_X
---------- ----------
2.5686E+33 3.4810E+35
1 row selected.
demo@ORA12C> set autotrace traceonly explain statistics
demo@ORA12C> select * from t1 where x between &min_x and &max_x;
old 1: select * from t1 where x between &min_x and &max_x
new 1: select * from t1 where x between 2.5686E+33 and 3.4810E+35
99 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 103 | 2472 | 104 (3)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 103 | 2472 | 104 (3)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("X"<=3.4810E+35 AND "X">=2.5686E+33)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
444 consistent gets
0 physical reads
0 redo size
3114 bytes sent via SQL*Net to client
552 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
99 rows processed
demo@ORA12C> set autotrace off
demo@ORA12C>
demo@ORA12C> select min(x) min_x,max(x) max_x
2 from ( select x from t2
3 order by x
4 fetch first 100 row only );
MIN_X MAX_X
---------- ----------
1 100
1 row selected.
demo@ORA12C>
demo@ORA12C> set autotrace traceonly explain statistics
demo@ORA12C> select * from t2 where x between &min_x and &max_x;
old 1: select * from t2 where x between &min_x and &max_x
new 1: select * from t2 where x between 1 and 100
100 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1879001825
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100 | 700 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 100 | 700 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T2_PK | 100 | | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("X">=1 AND "X"<=100)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
1647 bytes sent via SQL*Net to client
552 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
100 rows processed
demo@ORA12C> set autotrace off
demo@ORA12C>
GUID’s are
Randomly unique values
Will insert randomly across the entire breadth of the index.
will need the entire index in memory in order to say “we do no physical reads on the index during an insert”
These values are NOT monotonically increasing values
They have a terrific impact on the clustering factor of the index (close to the number of rows - so range scans are not likely possible).
Index will be larger in size when compare to sequence based index, will end up with 50-50 index splits ( half of the index will be empty at any time – that’s ok – don’t rebuild them to reclaim the space, that will only be a waste of time)
Sequences are
Sequentially unique values
As you insert – the values are increasing, you only hit the right hand size of the index.
Only the right hand side of the index in the cache, the left hand side – which you don’t query so much anymore since it is old data – it is rarely in the cache, hence when we insert we into this index – you will do very little if any physical IO.
These values are monotonically increasing values ( as you insert into it, the values are increasing and hit the right hand side of index)
They will end up with an appealing clustering factor of the index (close to the number of blocks – so range scans are likely possible)
Index will be thin, will end up with 90-10 split ups