TestingThis is a featured page

1 The importance of testing techniques

Test is related with the techniques needed to test any hypothesis. You can’t find all the answers you need in the documentation and books.
The problem I personally had is the impossibility to test by myself, and being force to be asking or searching readings about topics I could easily test by myself saving a lot of time, and getting a lot of accuracy and confidence in what I do.
Testing means you can answer questions like:
Why a reversed index is bigger?
Which is the difference between open_cursors and session_cached_cursors?
Etc.

1.A Tuning

You inevitably will reach a point where you CAN’T tune, if you can’t perform an adequate test.
For example you want to tune your index size, specifying the exact number length; honestly I don’t expect you are going to find a paragraph explaining you how much you can in space specifying the exact length of a number, so the only chance you have is to test it.
Even if you found this information, you can find this had changed in you current patch release or there is a bug on your platform invalidating this aftereffects.
But running a test you can see it
CREATE TABLE NUMBER_TEST
(
C_NUMBER_32 NUMBER(32,0) NOT NULL,
C_NUMBER_6 NUMBER(6,0) NOT NULL,
C_NUMBER NUMBER NOT NULL)
PCTFREE 10
/
INSERT INTO NUMBER_TEST
SELECT C_NUMBER,C_NUMBER,C_NUMBER FROM SOURCE_TEST;
CREATE INDEX FON.TEST_32 ON NUMBER_TEST(C_NUMBER_32);
CREATE INDEX FON.TEST_6 ON NUMBER_TEST(C_NUMBER_6);
CREATE INDEX FON.TEST_ ON NUMBER_TEST(C_NUMBER);
SELECT SEGMENT_NAME,SUM(BYTES)/1024/1024
FROM DBA_SEGMENTS
WHERE SEGMENT_NAME LIKE 'TEST%'
GROUP BY SEGMENT_NAME;
TEST_ 6,75
TEST_32 6,75
TEST_6 6,75
The output is enough, you don’t have to loose hours changing your tables to specify the exact number, because you don’t get any improvement, at least not in index size.
Only when you can measure an interesting improvement specifying the exact number of decimal, you can start to evaluate the change.

2 Use the second test to compare performance

I want you pay attention how different can be the performance measure, between the first and the second test.
So if you want to compare two different tests, is better you compare the second tests of each. The exception is when you want to test the first execution, this can require to restart your database several times.
NORMAL INSERT Test1 Test2 Test3
recursive calls 1724 0 0
db block gets 5181 3058 3057
consistent gets 1361 1070 1069
physical reads 225 0 0
redo size
2,953,548 2,848,720 2,843,936
APPEND INSERT Test1 Test2 Test3
Recursive calls 966 0 0
db block gets 1092 140 140
consistent gets 759 346 346
physical reads 0 0 0
redo size
3,071,888 2,983,528 2,983,528
APP INS NOLOG Test1 Test2 Test3
Recursive calls 1,327 0 0
db block gets 1,103 141 141
consistent gets 892 346 346
physical reads 0 0 0
redo size 81,504 80,944 80,944
If you compare, you will see starting from the second execution the rest seems to be similar.
So unless you want to time the first execution, you should compare the second execution of every scenario to analyze the test.
In this example you can see the third test seems to be the best, but nologging tables is not advisable if you are running archivelog mode, and you should be running on archivelog.
The description of the test
First Execution Normal Insert
SQL> INSERT INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
0 INSERT STATEMENT Optimizer=CHOOSE (Cost=34 Card=16507 Bytes=2343994)
1 0 TABLE ACCESS (FULL) OF 'CUENTAS_ME' (Cost=34 Card=16507 Bytes=2343994)
Statistics
----------------------------------------------------------
1724 recursive calls
5181 db block gets
1361 consistent gets
225 physical reads
2953548 redo size
628 bytes sent via SQL*Net to client
549 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
16507 rows processed
SQL> ROLLBACK;
Second Execution Normal Insert
SQL> INSERT INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
0 INSERT STATEMENT Optimizer=CHOOSE (Cost=34 Card=16507 Bytes= 2343994)
1 0 TABLE ACCESS (FULL) OF 'CUENTAS_ME' (Cost=34 Card=16507 Bytes=2343994)
Statistics
----------------------------------------------------------
0 recursive calls
3058 db block gets
1070 consistent gets
0 physical reads
2848720 redo size
633 bytes sent via SQL*Net to client
549 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
16507 rows processed
SQL> ROLLBACK;
Third Execution Normal Insert
SQL> INSERT INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
0 INSERT STATEMENT Optimizer=CHOOSE (Cost=34 Card=16507 Bytes= 2343994)
1 0 TABLE ACCESS (FULL) OF 'CUENTAS_ME' (Cost=34 Card=16507 Bytes=2343994)
Statistics
----------------------------------------------------------
0 recursive calls
3057 db block gets
1069 consistent gets
0 physical reads
2843936 redo size
636 bytes sent via SQL*Net to client
549 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
16507 rows processed
First Execution Append Insert
SQL> INSERT /*+ APPEND */ INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
ERROR:ORA-12838: no se puede leer/modificar un objeto despuÚs de modificarlo en paralelo
SP2-0612: Error al generar el informe AUTOTRACE EXPLAIN
Statistics
----------------------------------------------------------
966 recursive calls
1092 db block gets
759 consistent gets
0 physical reads
3071888 redo size
620 bytes sent via SQL*Net to client
563 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
16507 rows processed
SQL> ROLLBACK;
Second Execution Append Insert
SQL> INSERT /*+ APPEND */ INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
ERROR:ORA-12838: no se puede leer/modificar un objeto despuÚs de modificarlo en paralelo
SP2-0612: Error al generar el informe AUTOTRACE EXPLAIN
Statistics
----------------------------------------------------------
0 recursive calls
140 db block gets
346 consistent gets
0 physical reads
2983528 redo size
620 bytes sent via SQL*Net to client
563 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
16507 rows processed
SQL> ROLLBACK;
Third Execution Append Insert
SQL> INSERT /*+ APPEND */ INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
ERROR: ORA-12838: no se puede leer/modificar un objeto despuÚs de modificarlo en paralelo
SP2-0612: Error al generar el informe AUTOTRACE EXPLAIN
Statistics
----------------------------------------------------------
0 recursive calls
140 db block gets
346 consistent gets
0 physical reads
2983528 redo size
620 bytes sent via SQL*Net to client
563 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
16507 rows processed
First Execution Append Insert (NOLOGGING TABLE)
SQL> ALTER TABLE CUENTAS_BACK NOLOGGING;
Tabla modificada.
SQL> ROLLBACK;
Rollback terminado.
SQL> INSERT /*+ APPEND */ INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
ERROR:ORA-12838: no se puede leer/modificar un objeto despuÚs de modificarlo en paralelo
SP2-0612: Error al generar el informe AUTOTRACE EXPLAIN
Statistics
----------------------------------------------------------
1327 recursive calls
1103 db block gets
892 consistent gets
0 physical reads
81504 redo size
620 bytes sent via SQL*Net to client
563 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
16507 rows processed
SQL> ROLLBACK;
Second & Third Execution Append Insert (NOLOGGING TABLE)
SQL> INSERT /*+ APPEND */ INTO CUENTAS_BACK SELECT * FROM CUENTAS_ME;
16507 filas creadas.
Execution Plan
----------------------------------------------------------
ERROR:ORA-12838: no se puede leer/modificar un objeto despuÚs de modificarlo enparalelo
SP2-0612: Error al generar el informe AUTOTRACE EXPLAIN
Statistics
----------------------------------------------------------
0 recursive calls
141 db block gets
346 consistent gets
0 physical reads
944 redo size
621 bytes sent via SQL*Net to client
563 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
16507 rows processed

3 Setting environment for testing

3.A Resetting Memory: Shared Pool and Buffer Cache

Going to the previous example if you want to compare the first execution, when you need to bind again, and load from disk data again. You can do this restarting the database, or you can resent the buffer pool cache and shared pool cache in the following way.
Flushing shared pool command is an example about to test your testing techniques, flushing shared pool don’t flush everything, a simple select * from v$sql can shows it.
Flushing buffer cache will flush only unpinned buffers, x$bh.state is set to 0.
I tested this functionality and to compare some binds test, I had to restart the database. 3.A.i Shared Pool -- Yes,execute three times
ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SYSTEM FLUSH SHARED_POOL; 3.A.ii Buffer Cache On 10g
ALTER SYSTEM FLUSH BUFFER_CACHE;
On 9.2
ALTER SESSION SET EVENTS = ' immediate trace name flush_cache ';

3.B Disabling features

3.B.i OPTIMIZER_FEATURES_ENABLE parameter OPTIMIZER_FEATURES_ENABLE=
{ 8.0.0 | 8.0.3 | 8.0.4| 8.0.5 | 8.0.6 | 8.0.7 | 8.1.0 | 8.1.3 | 8.1.4 |
8.1.5 | 8.1.6 | 8.1.7 | 9.0.0 | 9.0.1 | 9.2.0 |10.0.0 | 10.1.0 }
Allows to disable new optimizer features. 3.B.ii Hidden Parameters To run some test you may need to disable some specific features using hidden parameters. This means you have to search and set the parameter and test if the specific hidden parameter, really disables what you need.
You can find information about hidden parameters in the view M.HIDDEN_PARAMETERS.

3.C Statistics ****falta

Copy statistics from production database example

4 Create Database and schema objects to test

Some test needs specific database and/or schema structures to test.

4.A Database Objects

For example if you want to test freelists, you must analyze if your tablespace is auto managed or not.

4.B Schema Objects

4.B.i Tables having one record per block To analyze dumps or to make easier the cound you can create tables with one record per block.
create table test_1row_1block pctfree 99 pctused 0 as select * from dba_objects where rownum <11 ; 4.B.ii Index leaf blocks To create a lot of leaf blocks for testing, you can specify a value of x higher than 50.
Create index idx on table tbl(col1,col2) pctfree x;

5 Generating test data

5.A Using dba_objects

Because dba_objects views has columns with data enough to run several tests, you can use it as the fastest way to generate data.
For example to generate an exact amount of record: 1,000,000 of records
DROP TABLE TEST.TEST_A;
CREATE TABLE TEST.TEST_A AS
SELECT A.*
FROM DBA_OBJECTS A, ( SELECT 1 FROM DBA_OBJECTS WHERE ROWNUM <= (SELECT CEIL(1000000/COUNT(*)) FROM DBA_OBJECTS ) )
WHERE ROWNUM <1000000+1;
SELECT COUNT(*) FROM TEST.TEST_A;
1000000

5.B DBMS_RANDOM

DBMS_RANDOM package generates random values, to get a more specific random data. 5.B.i Numbers Specifying a range of number you get a range of random number in that range.
SQL> select dbms_random.value(1,5) from dba_objects where rownum <3;
DBMS_RANDOM.VALUE(1,5)
----------------------
1.2155864
2.0816935
Under the same dbms_random.seed(x), you get the same output;
SQL> exec dbms_random.seed(3);
SQL> select dbms_random.value(1,5) from dba_objects where rownum <3;
DBMS_RANDOM.VALUE(1,5)
----------------------
3.5895074
3.2496582
SQL> exec dbms_random.seed(3);
SQL> select dbms_random.value(1,5) from dba_objects where rownum <3;
DBMS_RANDOM.VALUE(1,5)
----------------------
3.5895074
3.2496582
5.B.i.a Precision SQL> select val,round(val,2),trunc(val,2),round(val,-1),trunc(val,-1) FROM
2 ( select dbms_random.value(1100,1300) val FROM DBA_OBJECTS where rownum<15);
1283,94219 1283,94 1283,94 1280 1280
1171,9224 1171,92 1171,92 1170 1170
1127,31118 1127,31 1127,31 1130 1120
1154,18187 1154,18 1154,18 1150 1150
1156,22124 1156,22 1156,22 1160 1150
1114,12243 1114,12 1114,12 1110 1110
1222,22804 1222,23 1222,22 1220 1220
1203,15785 1203,16 1203,15 1200 1200
1260,75784 1260,76 1260,75 1260 1260
1147,20424 1147,2 1147,2 1150 1140
1240,95481 1240,95 1240,95 1240 1240
1143,17473 1143,17 1143,17 1140 1140
1289,54102 1289,54 1289,54 1290 1280
1267,0952 1267,1 1267,09 1270 1260
5.B.ii Strings dbms_random.String(Format, length );
'u', 'U' - returning string in uppercase alpha characters
SQL> select dbms_random.string('u',10) from dba_objects where rownum <3;
DBMS_RANDOM.STRING('U',10)
---------------------------------------------------------------------------
STWPBBPYSE
UJMYKAZAJX
'l', 'L' - returning string in lowercase alpha characters
SQL> select dbms_random.string('l',10) from dba_objects where rownum <3;
DBMS_RANDOM.STRING('L',10)
---------------------------------------------------------------------------
oovfyhsrpy
jngcguioas
'a', 'A' - returning string in mixed case alpha characters
SQL> select dbms_random.string('a',10) from dba_objects where rownum <3;
DBMS_RANDOM.STRING('A',10)
---------------------------------------------------------------------------
IWKdQgvviD
rDSXogBeNi
'x', 'X' - returning string in uppercase alpha-numeric
SQL> select dbms_random.string('x',10) from dba_objects where rownum <3;
DBMS_RANDOM.STRING('X',10)
---------------------------------------------------------------------------
0YGZA15THE
Q4GKHW6Q4K
'p', 'P' - returning string in any printable characters.
SQL> select dbms_random.string('p',10) from dba_objects where rownum <3;
DBMS_RANDOM.STRING('P',10)
---------------------------------------------------------------------------
ATf|F-,:bQ
K@PMaKLBDl

5.C Using P_DATAGEN package

This is a very simple package, I did on the fly, to generate arithmetic and logarithmic increases in the number and string data. This is enough to small and medium test tables, you can modify to meet your specific needs. 5.C.i Number sequences 5.C.i.a Correlative SQL> exec M.P_DATAGEN.Initialize;
SQL> select m.p_datagen.correlative FROM DBA_OBJECTS where rownum<15;
CORRELATIVE
-----------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
5.C.i.b Arithmetic The number of repetitions increase in this way 1,2,3,4,5,…
SQL> exec M.P_DATAGEN.Initialize;
SQL> select m.p_datagen.arithmetic FROM DBA_OBJECTS where rownum<15;
ARITHMETIC
----------
0
1
1
1
2
2
2
2
3
3
3
3
3
4
5.C.i.c Logarithmic The number or repetitions increase in this way, 1, 1+2=3, …
SQL> exec M.P_DATAGEN.Initialize;
SQL> SELECT M.P_DATAGEN.Logarithmic FROM DBA_OBJECTS where rownum<15;
LOGARITHMIC
-----------
0
1
1
1
2
2
2
2
2
3
3
3
3
3
5.C.i.d Repetition To create effect like clustering you can specify the maximum number, before restarting the cound.
exec M.P_DATAGEN.Initialize;
SELECT M.P_DATAGEN.Logarithmic(2) FROM DBA_OBJECTS where rownum<15;
M.P_DATAGEN.LOGARITHMIC(2)
--------------------------
0
1
1
1
2
2
2
2
2
1
1
1
1
1
5.C.i.e Negatives SQL> exec M.P_DATAGEN.Initialize;
SQL> select m.p_datagen.correlative*-1 FROM DBA_OBJECTS where rownum<15;
-1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
5.C.i.f Random sequences SQL> exec M.P_DATAGEN.Initialize;
SQL> select TRUNC(DBMS_RANDOM.VALUE(CORR-2,CORR+2)) FROM
2 ( select m.p_datagen.correlative corr FROM DBA_OBJECTS where rownum<15);
1
5
4
6
5
7
7
8
9
12
11
13
15
14
5.C.ii Character sequences SQL> SELECT M.P_DATAGEN.NUMBER_TO_CHAR(ROWNUM-1) FROM DBA_OBJECTS where rownum <15;
a
b
c
d
e
f
g
h
i
j
k
l
m
n
By default uses this characters cCharacters := 'abcdefghijklmnopqrstuvwxyz1234567890';
But you can change this specifying the characters you want
SELECT M.P_DATAGEN.NUMBER_TO_CHAR(ROWNUM-1,'01') FROM DBA_OBJECTS where rownum <15;
0
1
10
11
100
101
110
111
1000
1001
1010
1011
1100
1101
5.C.iii Date sequences You can generate dates using m.P_DATAGEN.F_DATE and timestamps m.P_DATAGEN.F_TIMESTAMP.
The reason to create this functions is to allow randomly generating the hour, minutes, seconds. If you don’t want that data randomly generated, better you get numbers and convert to date using TO_DATE(NUMBER,’j’) 5.C.iii.a Random Time sequences SQL> SELECT TO_CHAR(m.P_DATAGEN.F_DATE (SYSDATE+ROWNUM,SYSDATE+ROWNUM),'DD-MM-YYYY HH:MI:SS') FECHA
2 FROM DBA_OBJECTS WHERE ROWNUM <15;
10-02-2005 06:35:27
11-02-2005 02:15:05
12-02-2005 10:58:29
13-02-2005 09:09:20
14-02-2005 09:12:13
15-02-2005 12:37:37
16-02-2005 08:44:34
17-02-2005 07:34:29
18-02-2005 02:28:08
19-02-2005 05:39:35
20-02-2005 03:03:29
21-02-2005 06:54:29
22-02-2005 09:07:18
23-02-2005 05:06:38
5.C.iii.b Only date sequence SQL> exec m.p_datagen.nCorr := to_char(sysdate,'j');
SQL> select to_date(m.p_datagen.correlative,'j') FROM DBA_OBJECTS where rownum<15;
10/02/05
11/02/05
12/02/05
13/02/05
14/02/05
15/02/05
16/02/05
17/02/05
18/02/05
19/02/05
20/02/05
21/02/05
22/02/05
23/02/05
5.C.iii.c Trunc Before using trunc on dates, you should understand how it works
SQL> SELECT TO_CHAR(FECHA,'DDMONYYYY HH:MI:SS') FECHA,
2 TO_CHAR(TRUNC(FECHA,'YYYY'),'DDMONYYYY HH:MI:SS') C_YYYY,
3 TO_CHAR(TRUNC(FECHA,'MM'),'DDMONYYYY HH:MI:SS') C_MM,
4 TO_CHAR(TRUNC(FECHA,'HH'),'DDMONYYYY HH:MI:SS') C_HH
5 FROM ( SELECT m.P_DATAGEN.F_DATE(SYSDATE-800,SYSDATE-700) FECHA FROM DUAL);
24ENE2003 03:54:12 01ENE2003 12:00:00 01ENE2003 12:00:00 24ENE2003 11:00:00

5.D Analyzing column data distribution

5.D.i Data Order This query compares each value with the previous, if the previous is higher, it adds one to NO_ASCEN, the reversal for the colum NO_DESCEN, and if is equal to the previous, the column EQUAL adds a value.
20:52:04 SQL> select sum(ascen) no_ascen,sum(descen) no_descen,sum(equal) equal,count(*) total from
20:52:05 2 (
20:52:05 3 select object_id,lag(object_id,1,null) over (partition by 1 order by object_id ),
20:52:05 4 case when object_id < lag(object_id,1,null) over (partition by 1 order by object_id ) then 1 else 0 end as
cen,
20:52:05 5 case when object_id > lag(object_id,1,null) over (partition by 1 order by object_id ) then 1 else 0 end de
scen,
20:52:05 6 case when object_id = lag(object_id,1,null) over (partition by 1 order by object_id ) then 1 else 0 end eq
ual
20:52:05 7 from cachun.test_a)
20:52:06 8 /
NO_ASCEN NO_DESCEN EQUAL TOTAL
---------- ---------- ---------- ----------
0 50599 0 50600

6 Multiple user Testing Techniques

6.A Running several tasks at the same time

This technique comes from Tom Kyte.
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:9088073430469#9099572884547


No user avatar
juancarlosreyesp
Latest page update: made by juancarlosreyesp , Sep 30 2008, 9:48 PM EDT (about this update About This Update juancarlosreyesp Edited by juancarlosreyesp

2647 words added

view changes

- complete history)
Keyword tags: None
More Info: links to this page
There are no threads for this page.  Be the first to start a new thread.