CREATE TYPE all_obj_type IS OBJECT
(
OWNER VARCHAR2(30),
OBJECT_NAME VARCHAR2(30),
SUBOBJECT_NAME VARCHAR2(30),
OBJECT_ID NUMBER,
DATA_OBJECT_ID NUMBER,
OBJECT_TYPE VARCHAR2(19),
CREATED DATE,
LAST_DDL_TIME DATE
);
/
CREATE OR REPLACE TYPE all_obj_tt IS TABLE OF all_obj_type;
/
CREATE OR REPLACE FUNCTION non_pipe_fnc
RETURN all_obj_tt IS
all_obj all_obj_tt := all_obj_tt();
BEGIN
FOR r IN (SELECT * FROM ALL_OBJECTS)
LOOP
all_obj.EXTEND;
all_obj(all_obj.COUNT) := all_obj_type(r.OWNER,r.OBJECT_NAME,r.SUBOBJECT_NAME,r.OBJECT_ID,r.DATA_OBJECT_ID,r.OBJECT_TYPE,r.CREATED,r.LAST_DDL_TIME);
END LOOP;
RETURN all_obj;
END non_pipe_fnc;
/
CREATE OR REPLACE FUNCTION pipe_fnc
RETURN all_obj_tt
PIPELINED IS
BEGIN
FOR r IN (SELECT * FROM ALL_OBJECTS)
LOOP
PIPE ROW(all_obj_type(r.OWNER,r.OBJECT_NAME,r.SUBOBJECT_NAME,r.OBJECT_ID,r.DATA_OBJECT_ID,r.OBJECT_TYPE,r.CREATED,r.LAST_DDL_TIME));
END LOOP;
RETURN;
END pipe_fnc;
/
scott@10G> exec runstats_pkg.rs_start;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.21
scott@10G> select * from TABLE(non_pipe_fnc());
41042 rows selected.
Elapsed: 00:00:03.64
Execution Plan
----------------------------------------------------------
Plan hash value: 1517095174
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8168 | 16336 | 24 (0)| 00:00:01 |
| 1 | COLLECTION ITERATOR PICKLER FETCH| NON_PIPE_FNC | | | | |
--------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
6794 recursive calls
0 db block gets
87847 consistent gets
101 physical reads
0 redo size
1587183 bytes sent via SQL*Net to client
3399 bytes received via SQL*Net from client
275 SQL*Net roundtrips to/from client
33 sorts (memory)
0 sorts (disk)
41042 rows processed
scott@10G> exec runstats_pkg.rs_middle;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.03
scott@10G> select * from TABLE(pipe_fnc());
41042 rows selected.
Elapsed: 00:00:02.84
Execution Plan
----------------------------------------------------------
Plan hash value: 2394767287
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8168 | 16336 | 25 (4)| 00:00:01 |
| 1 | COLLECTION ITERATOR PICKLER FETCH| PIPE_FNC | | | | |
----------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
5819 recursive calls
0 db block gets
86292 consistent gets
0 physical reads
0 redo size
1587183 bytes sent via SQL*Net to client
3399 bytes received via SQL*Net from client
275 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
41042 rows processed
Name Run1 Run2 Diff
STAT...session uga memory 261,856 0 -261,856
STAT...physical read total byt 851,968 0 -851,968
STAT...physical read bytes 851,968 0 -851,968
STAT...session pga memory 3,080,192 0 -3,080,192
STAT...session uga memory max 16,811,116 0 -16,811,116
STAT...session pga memory max 36,569,088 0 -36,569,088
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
266,350 266,319 -31 100.01%
PL/SQL procedure successfully completed.
Wednesday, March 31, 2010
Saturday, March 27, 2010
Bind Peeking
Bind peeking - it means when the query is first Hard parsed, the optimizer will peek at the binds in order to determine how to optimize the query. Its not at every parse, only at Hard parsing.
create table t
as
select 1 as id,a.*
from all_objects a;
update t set id = 99 where rownum = 1;
create index t_ind on t(id);
exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T',estimate_percent=>100,method_opt=>'for all indexed columns size 254',cascade=>true);
/* massively skewed data, index on t(id) should be used if ID is not 1..So we run these queries against this data */
variable x number;
exec :x := 1;
select * from t x_was_1 where id = :x;
exec :x := 99;
select * from t x_was_99 where id = :x;
/* Now we execute the same queries (soft parse) --but with the inputs flip flopped */
exec :x := 1;
select * from t x_was_99 where id = :x;
exec :x := 99;
select * from t x_was_1 where id = :x;
********************************************************************************
BEGIN :x := 1; END;
select *
from
t x_was_1 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.04 0.06 0 1073 0 51437
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.04 0.06 0 1073 0 51437
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
51437 TABLE ACCESS FULL T (cr=1073 pr=0 pw=0 time=34 us)
/* This is what expected, when the bind was set to 1 during Hard parse. A Full Table scan */
********************************************************************************
BEGIN :x := 99; END;
select *
from
t x_was_99 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 3 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 3 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID T (cr=3 pr=0 pw=0 time=30 us)
1 INDEX RANGE SCAN T_IND (cr=2 pr=0 pw=0 time=21 us)(object id 65996)
/* Expected plan with Bind is 99 - Index range scan */
********************************************************************************
BEGIN :x := 1; END;
select *
from
t x_was_99 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.07 0.09 0 1512 0 51437
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.07 0.09 0 1512 0 51437
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
51437 TABLE ACCESS BY INDEX ROWID T (cr=1512 pr=0 pw=0 time=102909 us)
51437 INDEX RANGE SCAN T_IND (cr=445 pr=0 pw=0 time=24 us)(object id 65996)
/* Here the bind variable is in fact 1, if you remember from the test case. The plan was fixed during the Hard parse and same got reused. */
********************************************************************************
BEGIN :x := 99; END;
select *
from
t x_was_1 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 735 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 735 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS FULL T (cr=735 pr=0 pw=0 time=50 us)
/* Same here now. Full table scan is not appropriate */
********************************************************************************
Binds - Are Mandatory on systems that parses many queries / second.
Binds - Not mandatory on systems that have many seconds between parses ( typically data warehouses, and queries that run for minutes or hours )
create table t
as
select 1 as id,a.*
from all_objects a;
update t set id = 99 where rownum = 1;
create index t_ind on t(id);
exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T',estimate_percent=>100,method_opt=>'for all indexed columns size 254',cascade=>true);
/* massively skewed data, index on t(id) should be used if ID is not 1..So we run these queries against this data */
variable x number;
exec :x := 1;
select * from t x_was_1 where id = :x;
exec :x := 99;
select * from t x_was_99 where id = :x;
/* Now we execute the same queries (soft parse) --but with the inputs flip flopped */
exec :x := 1;
select * from t x_was_99 where id = :x;
exec :x := 99;
select * from t x_was_1 where id = :x;
********************************************************************************
BEGIN :x := 1; END;
select *
from
t x_was_1 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.04 0.06 0 1073 0 51437
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.04 0.06 0 1073 0 51437
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
51437 TABLE ACCESS FULL T (cr=1073 pr=0 pw=0 time=34 us)
/* This is what expected, when the bind was set to 1 during Hard parse. A Full Table scan */
********************************************************************************
BEGIN :x := 99; END;
select *
from
t x_was_99 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 3 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 3 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID T (cr=3 pr=0 pw=0 time=30 us)
1 INDEX RANGE SCAN T_IND (cr=2 pr=0 pw=0 time=21 us)(object id 65996)
/* Expected plan with Bind is 99 - Index range scan */
********************************************************************************
BEGIN :x := 1; END;
select *
from
t x_was_99 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.07 0.09 0 1512 0 51437
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.07 0.09 0 1512 0 51437
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
51437 TABLE ACCESS BY INDEX ROWID T (cr=1512 pr=0 pw=0 time=102909 us)
51437 INDEX RANGE SCAN T_IND (cr=445 pr=0 pw=0 time=24 us)(object id 65996)
/* Here the bind variable is in fact 1, if you remember from the test case. The plan was fixed during the Hard parse and same got reused. */
********************************************************************************
BEGIN :x := 99; END;
select *
from
t x_was_1 where id = :x
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 735 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 735 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 54
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS FULL T (cr=735 pr=0 pw=0 time=50 us)
/* Same here now. Full table scan is not appropriate */
********************************************************************************
Binds - Are Mandatory on systems that parses many queries / second.
Binds - Not mandatory on systems that have many seconds between parses ( typically data warehouses, and queries that run for minutes or hours )
Thursday, March 25, 2010
Global Variables in Packages
I like to say from time to time "I learn something new about Oracle every day". I am learned something new about PL/SQL that i was not aware of.
scott@10G> create or replace package my_pkg as
2 procedure p;
3 end my_pkg;
4 /
Package created.
Elapsed: 00:00:00.15
scott@10G> create or replace package body my_pkg as
2 g_global number;
3
4 procedure private(l_num in number) as
5 begin
6 dbms_output.put_line (' The value of l_num before was '||l_num);
7 g_global := 65;
8 dbms_output.put_line (' The value of l_num after was '||l_num);
9 end;
10
11 procedure p as
12 begin
13 g_global := 55;
14 private(g_global);
15 end p;
16
17 end my_pkg;
18 /
Package body created.
Elapsed: 00:00:00.03
scott@10G> exec my_pkg.p;
The value of l_num before was 55
The value of l_num after was 65
PL/SQL procedure successfully completed.
It comes from the fact that IN parameters are passed by reference (as a pointer).The other approach, when FORCED to use globals, assign them to another variable OR cause a temporary to be created (|| '' for strings, +0 for dates, numbers...)
scott@10G> create or replace package my_pkg as
2 procedure p;
3 end my_pkg;
4 /
Package created.
Elapsed: 00:00:00.00
scott@10G> create or replace package body my_pkg as
2 g_global number;
3
4 procedure private(l_num in number) as
5 begin
6 dbms_output.put_line (' The value of l_num before was '||l_num);
7 g_global := 65;
8 dbms_output.put_line (' The value of l_num after was '||l_num);
9 end;
10
11 procedure p as
12 begin
13 g_global := 55;
14 private(g_global+0);
15 end p;
16
17 end my_pkg;
18 /
Package body created.
Elapsed: 00:00:00.01
scott@10G> exec my_pkg.p;
The value of l_num before was 55
The value of l_num after was 55
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
So, one approach is either try to avoid global variables in packages or when Forced to use globals assign them to another variable OR cause a temporary to be created. as i did above.
scott@10G> create or replace package my_pkg as
2 procedure p;
3 end my_pkg;
4 /
Package created.
Elapsed: 00:00:00.15
scott@10G> create or replace package body my_pkg as
2 g_global number;
3
4 procedure private(l_num in number) as
5 begin
6 dbms_output.put_line (' The value of l_num before was '||l_num);
7 g_global := 65;
8 dbms_output.put_line (' The value of l_num after was '||l_num);
9 end;
10
11 procedure p as
12 begin
13 g_global := 55;
14 private(g_global);
15 end p;
16
17 end my_pkg;
18 /
Package body created.
Elapsed: 00:00:00.03
scott@10G> exec my_pkg.p;
The value of l_num before was 55
The value of l_num after was 65
PL/SQL procedure successfully completed.
It comes from the fact that IN parameters are passed by reference (as a pointer).The other approach, when FORCED to use globals, assign them to another variable OR cause a temporary to be created (|| '' for strings, +0 for dates, numbers...)
scott@10G> create or replace package my_pkg as
2 procedure p;
3 end my_pkg;
4 /
Package created.
Elapsed: 00:00:00.00
scott@10G> create or replace package body my_pkg as
2 g_global number;
3
4 procedure private(l_num in number) as
5 begin
6 dbms_output.put_line (' The value of l_num before was '||l_num);
7 g_global := 65;
8 dbms_output.put_line (' The value of l_num after was '||l_num);
9 end;
10
11 procedure p as
12 begin
13 g_global := 55;
14 private(g_global+0);
15 end p;
16
17 end my_pkg;
18 /
Package body created.
Elapsed: 00:00:00.01
scott@10G> exec my_pkg.p;
The value of l_num before was 55
The value of l_num after was 55
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
So, one approach is either try to avoid global variables in packages or when Forced to use globals assign them to another variable OR cause a temporary to be created. as i did above.
Wednesday, March 24, 2010
SQLLDR Defaults to CHAR(255)
The default length of input fields is 255 characters. If your field is longer than this, you will receive an error message:
scott@10G> select dbms_metadata.get_ddl('TABLE','T') from dual;
DBMS_METADATA.GET_DDL('TABLE','T')
--------------------------------------------------------------------------
CREATE TABLE "SCOTT"."T"
( "X" NUMBER,
"Y" DATE,
"Z" VARCHAR2(4000)
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS_DATA"
load data
infile *
into table t
truncate
fields terminated by ','
(
x ,
y " to_date(:y,'mm/dd/yyyy ') " ,
z
)
begindata
1,02/03/2010,VERSION INFORMATION:TNS for 32-bit Windows: Version 10.1.0.2.0 - Production:Oracle Bequeath NT Protocol Adapter for 32-bit Windows: Version 10.1.0.2.0 - ProductionTime: 09-FEB-2009 11:12:21Tracing not turned on.TNS-12560: TNS:protocol adapter errorTNS:protocol adapter error
Table T, loaded from every logical record.
Insert option in effect for this table: TRUNCATE
Column Name Position Len Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
X FIRST * , CHARACTER
Y NEXT * , CHARACTER
SQL string for column : " to_date(:y,'mm/dd/yyyy ') "
Z NEXT * , CHARACTER
Record 1: Rejected - Error on table T, column Z.
Field in data file exceeds maximum length
This does not mean the data will not fit into the database column, but rather SQLLDR was expecting 255 bytes or less of input data, and received somewhat more than that. The solution is to simply use CHAR(N) in the control file, where N is big enough to accommodate the largest field length in the input file.
load data
infile *
into table t
truncate
fields terminated by ','
(
x ,
y " to_date(:y,'mm/dd/yyyy ') " ,
z char(10000)
)
begindata
1,02/03/2010,VERSION INFORMATION:TNS for 32-bit Windows: Version 10.1.0.2.0 - Production:Oracle Bequeath NT Protocol Adapter for 32-bit Windows: Version 10.1.0.2.0 - ProductionTime: 09-FEB-2009 11:12:21Tracing not turned on.TNS-12560: TNS:protocol adapter errorTNS:protocol adapter error
scott@10G> select x,y,length(z) from T;
X Y LENGTH(Z)
---------- --------- ----------
1 03-FEB-10 274
scott@10G> select dbms_metadata.get_ddl('TABLE','T') from dual;
DBMS_METADATA.GET_DDL('TABLE','T')
--------------------------------------------------------------------------
CREATE TABLE "SCOTT"."T"
( "X" NUMBER,
"Y" DATE,
"Z" VARCHAR2(4000)
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS_DATA"
load data
infile *
into table t
truncate
fields terminated by ','
(
x ,
y " to_date(:y,'mm/dd/yyyy ') " ,
z
)
begindata
1,02/03/2010,VERSION INFORMATION:TNS for 32-bit Windows: Version 10.1.0.2.0 - Production:Oracle Bequeath NT Protocol Adapter for 32-bit Windows: Version 10.1.0.2.0 - ProductionTime: 09-FEB-2009 11:12:21Tracing not turned on.TNS-12560: TNS:protocol adapter errorTNS:protocol adapter error
Table T, loaded from every logical record.
Insert option in effect for this table: TRUNCATE
Column Name Position Len Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
X FIRST * , CHARACTER
Y NEXT * , CHARACTER
SQL string for column : " to_date(:y,'mm/dd/yyyy ') "
Z NEXT * , CHARACTER
Record 1: Rejected - Error on table T, column Z.
Field in data file exceeds maximum length
This does not mean the data will not fit into the database column, but rather SQLLDR was expecting 255 bytes or less of input data, and received somewhat more than that. The solution is to simply use CHAR(N) in the control file, where N is big enough to accommodate the largest field length in the input file.
load data
infile *
into table t
truncate
fields terminated by ','
(
x ,
y " to_date(:y,'mm/dd/yyyy ') " ,
z char(10000)
)
begindata
1,02/03/2010,VERSION INFORMATION:TNS for 32-bit Windows: Version 10.1.0.2.0 - Production:Oracle Bequeath NT Protocol Adapter for 32-bit Windows: Version 10.1.0.2.0 - ProductionTime: 09-FEB-2009 11:12:21Tracing not turned on.TNS-12560: TNS:protocol adapter errorTNS:protocol adapter error
scott@10G> select x,y,length(z) from T;
X Y LENGTH(Z)
---------- --------- ----------
1 03-FEB-10 274
Bind variables
Bind Variables are important because one of the design feature in Oracle is ability to reuse the optimizer plans whenever possible. whenever you submit any SQL or PL/SQL blocks to database, Oracle will look if the query is already parsed and optimized (Shared pool) if it finds then the execution plan can be reused. If it cannot find then Oracle Hard parses the query, performs security checks and optimizes the plan and so on..This not only consumes CPU but tends to lock the portion of the library cache for relatively long periods. The more people hard parsing the query increases then longer the wait.
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
PL/SQL Release 9.2.0.8.0 - Production
CORE 9.2.0.8.0 Production
TNS for 32-bit Windows: Version 9.2.0.8.0 - Production
NLSRTL Version 9.2.0.8.0 - Production
2 FROM dba_tablespaces
3 where tablespace_name ='DATA1';
TABLESPACE_NAME SEGMEN
------------------------------ ------
DATA1 MANUAL
Elapsed: 00:00:00.04
create table t(x number,y number,z number) tablespace DATA1 storage(freelists 5);
create global temporary table temp_sess
on commit preserve rows
as
select *
from v$session_event where 1 = 0;
2 select * from v$session_event
3 where sid = (select sid from v$mystat where rownum = 1);
12 rows created.
Elapsed: 00:00:00.06
2 l_value number;
3 begin
4 for i in 1..100000
5 loop
6 l_value := dbms_random.value;
7 execute immediate ' insert into t (x,y,z) values ('||l_value||','||l_value||','||l_value||')';
8 end loop;
9 end;
10 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:52.95
2 (nvl(aft.time_waited,0) - nvl(bfr.time_waited,0)) as time_waited
3 FROM V$SESSION_EVENT aft,temp_sess bfr
4 WHERE aft.SID = (select sid from v$mystat where rownum = 1)
5 and aft.event = bfr.event(+)
6 and abs(aft.total_waits - nvl(bfr.total_waits,0)) > 0 ;
EVENT TOTAL_WAITS TIME_WAITED
---------------------------------------------------------------- ----------- -----------
latch free 226 30
enqueue 3 5
free buffer waits 1 67
buffer busy waits 33 0
log file switch completion 2 6
db file sequential read 8 4
row cache lock 15 31
SQL*Net message to client 8 0
SQL*Net message from client 7 11895
9 rows selected.
The Oracle wait interface are documented in Oracle 9i Reference manual.
This latch free is actually a latch in shared sql area.So how this can be reduced. one way by using Bind variables.
Now using Bind variables Latch Free has gone down.
scott@9iR2> declare
2 l_value number;
3 begin
4 for i in 1..100000
5 loop
6 l_value := dbms_random.value;
7 execute immediate ' insert into t (x,y,z) values (:x,:y,:z) ' using l_value,l_value,l_value;
8 end loop;
9 end;
10 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:19.29
scott@9iR2> SELECT aft.event,(nvl(aft.total_waits,0) - nvl(bfr.total_waits,0)) as total_waits,
2 (nvl(aft.time_waited,0) - nvl(bfr.time_waited,0)) as time_waited
3 FROM V$SESSION_EVENT aft,temp_sess bfr
4 WHERE aft.SID = (select sid from v$mystat where rownum = 1)
5 and aft.event = bfr.event(+)
6 and abs(aft.total_waits - nvl(bfr.total_waits,0)) > 0 ;
EVENT TOTAL_WAITS TIME_WAITED
---------------------------------------------------------------------------
latch free 123 8
buffer busy waits 1000 350
log file switch completion 3 9
db file sequential read 677 373
SQL*Net message to client 5 0
SQL*Net message from client 4 4538
6 rows selected.
Elapsed: 00:00:00.04
Another way to drop this considerably is static SQL's in Pl/SQL block.
scott@9iR2> declare
2 l_value number;
3 begin
4 for i in 1..100000
5 loop
6 l_value := dbms_random.value;
7 insert into t (x,y,z) values (l_value,l_value,l_value);
8 end loop;
9 end;
10 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:07.55
scott@9iR2> SELECT aft.event,(nvl(aft.total_waits,0) - nvl(bfr.total_waits,0)) as total_waits,
2 (nvl(aft.time_waited,0) - nvl(bfr.time_waited,0)) as time_waited
3 FROM V$SESSION_EVENT aft,temp_sess bfr
4 WHERE aft.SID = (select sid from v$mystat where rownum = 1)
5 and aft.event = bfr.event(+)
6 and abs(aft.total_waits - nvl(bfr.total_waits,0)) > 0 ;
EVENT TOTAL_WAITS TIME_WAITED
-----------------------------------------------------------------------
enqueue 9 0
free buffer waits 5 70
write complete waits 1 20
buffer busy waits 3 0
log buffer space 7 64
log file switch completion 2 18
db file sequential read 2 1
SQL*Net message to client 5 0
SQL*Net message from client 4 3020
9 rows selected.
Now when executing static sql's in Pl./Sql block ( PL/SQL will cache my cursor for me – that is one of the major advantages of PL/SQL. This insert will typically be soft parsed once per session for me if it was in a
procedure ) . The latching is totally gone.
The above demonstrates that using Bind variable is crucial to performance.
Tuesday, March 23, 2010
Loading LOB data that is Out of Line
A Common scenario is to have data file that contains the name of the file to load, instead of having lob data mix with structured data. we can tell sqlldr how to parse the LOB data from its structured data using LOBFILE in sqlldr.
scott@10G> desc T;
Name Null? Type
----------------- -------- -------------
CREATED_BY VARCHAR2(30)
T_DATA CLOB
load data
infile *
truncate
into table t
(
created_by position(48:62),
x filler position(63:80),
t_data lobfile(x) terminated by eof)
begindata
09/15/2009 11:30 AM 544 BUILTIN\Administrators process_3121.log
09/15/2009 12:40 PM 550 BUILTIN\Administrators process_3122.log
09/15/2009 01:23 PM 550 BUILTIN\Administrators process_3123.log
09/15/2009 01:36 PM 550 BUILTIN\Administrators process_3124.log
09/15/2009 01:50 PM 550 BUILTIN\Administrators process_3125.log
09/15/2009 01:53 PM 550 BUILTIN\Administrators process_3126.log
09/15/2009 01:58 PM 550 BUILTIN\Administrators process_3127.log
09/15/2009 01:59 PM 550 BUILTIN\Administrators process_3128.log
09/15/2009 02:47 PM 550 BUILTIN\Administrators process_3129.log
09/15/2009 02:49 PM 550 BUILTIN\Administrators process_3130.log
09/15/2009 02:51 PM 553 BUILTIN\Administrators process_3131.log
09/15/2009 03:00 PM 553 BUILTIN\Administrators process_3132.log
09/15/2009 03:06 PM 553 BUILTIN\Administrators process_3133.log
09/15/2009 03:24 PM 553 BUILTIN\Administrators process_3134.log
09/15/2009 03:30 PM 553 BUILTIN\Administrators process_3135.log
09/15/2009 03:35 PM 553 BUILTIN\Administrators process_3136.log
09/15/2009 03:42 PM 553 BUILTIN\Administrators process_3137.log
09/15/2009 03:49 PM 553 BUILTIN\Administrators process_3138.log
09/15/2009 03:54 PM 553 BUILTIN\Administrators process_3139.log
09/15/2009 04:09 PM 553 BUILTIN\Administrators process_3140.log
09/15/2009 04:35 PM 553 BUILTIN\Administrators process_3141.log
09/15/2009 04:44 PM 553 BUILTIN\Administrators process_3142.log
09/15/2009 04:49 PM 553 BUILTIN\Administrators process_3143.log
09/15/2009 04:49 PM 553 BUILTIN\Administrators process_3144.log
09/15/2009 06:18 PM 553 BUILTIN\Administrators process_3161.log
09/15/2009 06:26 PM 553 BUILTIN\Administrators process_3162.log
09/15/2009 06:34 PM 553 BUILTIN\Administrators process_3163.log
11/18/2009 01:13 PM 67 BUILTIN\Administrators process_3184.log
11/18/2009 01:21 PM 67 BUILTIN\Administrators process_3185.log
11/18/2009 01:43 PM 67 BUILTIN\Administrators process_3186.log
11/18/2009 02:48 PM 67 BUILTIN\Administrators process_3187.log
11/18/2009 03:51 PM 67 BUILTIN\Administrators process_3188.log
11/18/2009 05:01 PM 67 BUILTIN\Administrators process_3189.log
11/18/2009 05:18 PM 67 BUILTIN\Administrators process_3190.log
11/18/2009 05:34 PM 67 BUILTIN\Administrators process_3191.log
11/18/2009 05:42 PM 67 BUILTIN\Administrators process_3192.log
11/18/2009 07:33 PM 67 BUILTIN\Administrators process_3193.log
11/18/2009 08:11 PM 67 BUILTIN\Administrators process_3194.log
11/23/2009 10:31 AM 366 BUILTIN\Administrators process_3204.log
11/23/2009 10:37 AM 469 BUILTIN\Administrators process_3205.log
11/30/2009 04:36 PM 67 BUILTIN\Administrators process_3224.log
12/08/2009 10:25 PM 761 BUILTIN\Administrators process_3245.log
12/11/2009 06:23 PM 67 BUILTIN\Administrators process_3246.log
12/11/2009 06:27 PM 67 BUILTIN\Administrators process_3247.log
12/11/2009 06:41 PM 67 BUILTIN\Administrators process_3248.log
12/11/2009 06:55 PM 67 BUILTIN\Administrators process_3249.log
12/11/2009 06:56 PM 67 BUILTIN\Administrators process_3250.log
12/17/2009 08:06 PM 67 BUILTIN\Administrators process_3264.log
02/11/2010 09:27 PM 67 BUILTIN\Administrators process_3304.log
02/11/2010 09:36 PM 67 BUILTIN\Administrators process_3305.log
02/11/2010 10:48 PM 67 BUILTIN\Administrators process_3306.log
02/12/2010 12:45 PM 67 BUILTIN\Administrators process_3324.log
02/12/2010 12:51 PM 67 BUILTIN\Administrators process_3325.log
02/12/2010 05:40 PM 67 BUILTIN\Administrators process_3326.log
02/16/2010 01:28 PM 67 BUILTIN\Administrators process_3344.log
scott@10G> select created_by,dbms_lob.getlength(t_data) as lob_length from T;
CREATED_BY LOB_LENGTH
------------------------------ ----------
Administrators 550
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 366
Administrators 469
Administrators 761
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 544
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 553
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
55 rows selected.
scott@10G> desc T;
Name Null? Type
----------------- -------- -------------
CREATED_BY VARCHAR2(30)
T_DATA CLOB
load data
infile *
truncate
into table t
(
created_by position(48:62),
x filler position(63:80),
t_data lobfile(x) terminated by eof)
begindata
09/15/2009 11:30 AM 544 BUILTIN\Administrators process_3121.log
09/15/2009 12:40 PM 550 BUILTIN\Administrators process_3122.log
09/15/2009 01:23 PM 550 BUILTIN\Administrators process_3123.log
09/15/2009 01:36 PM 550 BUILTIN\Administrators process_3124.log
09/15/2009 01:50 PM 550 BUILTIN\Administrators process_3125.log
09/15/2009 01:53 PM 550 BUILTIN\Administrators process_3126.log
09/15/2009 01:58 PM 550 BUILTIN\Administrators process_3127.log
09/15/2009 01:59 PM 550 BUILTIN\Administrators process_3128.log
09/15/2009 02:47 PM 550 BUILTIN\Administrators process_3129.log
09/15/2009 02:49 PM 550 BUILTIN\Administrators process_3130.log
09/15/2009 02:51 PM 553 BUILTIN\Administrators process_3131.log
09/15/2009 03:00 PM 553 BUILTIN\Administrators process_3132.log
09/15/2009 03:06 PM 553 BUILTIN\Administrators process_3133.log
09/15/2009 03:24 PM 553 BUILTIN\Administrators process_3134.log
09/15/2009 03:30 PM 553 BUILTIN\Administrators process_3135.log
09/15/2009 03:35 PM 553 BUILTIN\Administrators process_3136.log
09/15/2009 03:42 PM 553 BUILTIN\Administrators process_3137.log
09/15/2009 03:49 PM 553 BUILTIN\Administrators process_3138.log
09/15/2009 03:54 PM 553 BUILTIN\Administrators process_3139.log
09/15/2009 04:09 PM 553 BUILTIN\Administrators process_3140.log
09/15/2009 04:35 PM 553 BUILTIN\Administrators process_3141.log
09/15/2009 04:44 PM 553 BUILTIN\Administrators process_3142.log
09/15/2009 04:49 PM 553 BUILTIN\Administrators process_3143.log
09/15/2009 04:49 PM 553 BUILTIN\Administrators process_3144.log
09/15/2009 06:18 PM 553 BUILTIN\Administrators process_3161.log
09/15/2009 06:26 PM 553 BUILTIN\Administrators process_3162.log
09/15/2009 06:34 PM 553 BUILTIN\Administrators process_3163.log
11/18/2009 01:13 PM 67 BUILTIN\Administrators process_3184.log
11/18/2009 01:21 PM 67 BUILTIN\Administrators process_3185.log
11/18/2009 01:43 PM 67 BUILTIN\Administrators process_3186.log
11/18/2009 02:48 PM 67 BUILTIN\Administrators process_3187.log
11/18/2009 03:51 PM 67 BUILTIN\Administrators process_3188.log
11/18/2009 05:01 PM 67 BUILTIN\Administrators process_3189.log
11/18/2009 05:18 PM 67 BUILTIN\Administrators process_3190.log
11/18/2009 05:34 PM 67 BUILTIN\Administrators process_3191.log
11/18/2009 05:42 PM 67 BUILTIN\Administrators process_3192.log
11/18/2009 07:33 PM 67 BUILTIN\Administrators process_3193.log
11/18/2009 08:11 PM 67 BUILTIN\Administrators process_3194.log
11/23/2009 10:31 AM 366 BUILTIN\Administrators process_3204.log
11/23/2009 10:37 AM 469 BUILTIN\Administrators process_3205.log
11/30/2009 04:36 PM 67 BUILTIN\Administrators process_3224.log
12/08/2009 10:25 PM 761 BUILTIN\Administrators process_3245.log
12/11/2009 06:23 PM 67 BUILTIN\Administrators process_3246.log
12/11/2009 06:27 PM 67 BUILTIN\Administrators process_3247.log
12/11/2009 06:41 PM 67 BUILTIN\Administrators process_3248.log
12/11/2009 06:55 PM 67 BUILTIN\Administrators process_3249.log
12/11/2009 06:56 PM 67 BUILTIN\Administrators process_3250.log
12/17/2009 08:06 PM 67 BUILTIN\Administrators process_3264.log
02/11/2010 09:27 PM 67 BUILTIN\Administrators process_3304.log
02/11/2010 09:36 PM 67 BUILTIN\Administrators process_3305.log
02/11/2010 10:48 PM 67 BUILTIN\Administrators process_3306.log
02/12/2010 12:45 PM 67 BUILTIN\Administrators process_3324.log
02/12/2010 12:51 PM 67 BUILTIN\Administrators process_3325.log
02/12/2010 05:40 PM 67 BUILTIN\Administrators process_3326.log
02/16/2010 01:28 PM 67 BUILTIN\Administrators process_3344.log
scott@10G> select created_by,dbms_lob.getlength(t_data) as lob_length from T;
CREATED_BY LOB_LENGTH
------------------------------ ----------
Administrators 550
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 553
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 366
Administrators 469
Administrators 761
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 544
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 550
Administrators 553
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
Administrators 67
55 rows selected.
Monday, March 22, 2010
Data Unloader - Plsql utility
One thing SQLLDR does not do, and that Oracle supplies no tools for, is the unloading of data in a format understandable by SQLLDR. This would be useful for moving data from system to system without using EXP/IMP. We will develop a small PL/SQL utility that may be used to unload data on a server in a SQLLDR‐friendly format (Also this utility has some limitations, like handling LOBS, RAW & BFile)
create or replace package pkg_unloader as
procedure dump_data (
p_query in varchar2,
p_directory in varchar2 default 'DATA_PUMP_DIR', /* default directory for data pump in oracle 10g */
p_file_name in varchar2 default 'sample.dat',
p_delimited in varchar2 default '|',
p_status out number );
end pkg_unloader;
/
create or replace package body pkg_unloader as
procedure dump_data (
p_query in varchar2,
p_directory in varchar2 default 'DATA_PUMP_DIR',
p_file_name in varchar2 default 'sample.dat',
p_delimited in varchar2 default '|',
p_status out number ) /* 0 - Sucess / other than 0 is error */
as
l_exec_status number;
l_file_handle utl_file.file_type;
l_desc_tab dbms_sql.desc_tab;
l_column_count number ;
l_line varchar2(32760) := null;
l_column_value varchar2(4000);
g_cursor number := dbms_sql.open_cursor;
l_nls_values nls_database_parameters.value%type;
begin
p_status := 0;
select value
into l_nls_values
from nls_database_parameters
where parameter = 'NLS_DATE_FORMAT';
execute immediate ' alter session set nls_date_format = ''ddmmyyyyhh24miss'' ';
l_file_handle := utl_file.fopen (p_directory,p_file_name,'w',32760);
dbms_sql.parse(g_cursor,p_query,dbms_sql.native);
dbms_sql.describe_columns (g_cursor,l_column_count,l_desc_tab);
for i in 1..l_column_count
loop
dbms_sql.define_column (g_cursor,i,l_column_value,4000);
end loop;
l_exec_status := dbms_sql.execute(g_cursor);
while ( dbms_sql.fetch_rows(g_cursor) > 0 )
loop
l_line := null;
for i in 1..l_column_count
loop
dbms_sql.column_value(g_cursor,i,l_column_value);
l_line := l_line ||p_delimited||l_column_value;
end loop;
l_line := l_line || chr(13) || chr(10); /* line terminator in windows */
utl_file.put(l_file_handle,l_line);
end loop;
utl_file.fclose(l_file_handle);
execute immediate ' alter session set nls_date_format = '''|| l_nls_values ||'''';
exception
when others then
if dbms_sql.is_open(g_cursor) then
dbms_sql.close_cursor(g_cursor);
end if;
if utl_file.is_open (l_file_handle) then
utl_file.fclose(l_file_handle);
end if;
p_status := sqlcode;
raise_application_error ( -20458,sqlerrm);
end dump_data;
end pkg_unloader;
/
Sample output
scott@10G> declare
2 l_status number;
3 begin
4 pkg_unloader.dump_data('select * from emp',
5 'DATA_PUMP_DIR',
6 'emp.dat',
7 '|',
8 l_status );
9 end;
10 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
scott@10G> host
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\179818>d:
D:\>cd D:\oracle\product\10.2.0\admin\10g\dpdump
D:\oracle\product\10.2.0\admin\10G\dpdump>type emp.dat
|7782|CLARK|MANAGER|7839|09061981000000|2450||10
|7839|KING|PRESIDENT||17111981000000|5000|0|10
|7934|MILLER|CLERK|7782|23011982000000|1300||10
|7844|TURNER|SALESMAN|7698|08091981000000|1500|0|30
|7788|SCOTT|ANALYST|7566|19041987000000|3000||20
|7698|BLAKE|MANAGER|7839|01051981000000|2850||30
|7566|JONES|MANAGER|7839|02041981000000|2975||20
|7499|ALLEN|SALESMAN|7698|20021981000000|1600|300|30
|7521|WARD|SALESMAN|7698|22021981000000|1250|500|30
|7902|FORD|ANALYST|7566|03121981000000|3000||20
|7654|MARTIN|SALESMAN|7698|28091981000000|1250|1400|30
|7369|SMITH|CLERK|7902|17121980000000|800||20
|7876|ADAMS|CLERK|7788|23051987000000|1100||20
|7900|JAMES|CLERK|7698|03121981000000|950||30
D:\oracle\product\10.2.0\admin\10G\dpdump>
create or replace package pkg_unloader as
procedure dump_data (
p_query in varchar2,
p_directory in varchar2 default 'DATA_PUMP_DIR', /* default directory for data pump in oracle 10g */
p_file_name in varchar2 default 'sample.dat',
p_delimited in varchar2 default '|',
p_status out number );
end pkg_unloader;
/
create or replace package body pkg_unloader as
procedure dump_data (
p_query in varchar2,
p_directory in varchar2 default 'DATA_PUMP_DIR',
p_file_name in varchar2 default 'sample.dat',
p_delimited in varchar2 default '|',
p_status out number ) /* 0 - Sucess / other than 0 is error */
as
l_exec_status number;
l_file_handle utl_file.file_type;
l_desc_tab dbms_sql.desc_tab;
l_column_count number ;
l_line varchar2(32760) := null;
l_column_value varchar2(4000);
g_cursor number := dbms_sql.open_cursor;
l_nls_values nls_database_parameters.value%type;
begin
p_status := 0;
select value
into l_nls_values
from nls_database_parameters
where parameter = 'NLS_DATE_FORMAT';
execute immediate ' alter session set nls_date_format = ''ddmmyyyyhh24miss'' ';
l_file_handle := utl_file.fopen (p_directory,p_file_name,'w',32760);
dbms_sql.parse(g_cursor,p_query,dbms_sql.native);
dbms_sql.describe_columns (g_cursor,l_column_count,l_desc_tab);
for i in 1..l_column_count
loop
dbms_sql.define_column (g_cursor,i,l_column_value,4000);
end loop;
l_exec_status := dbms_sql.execute(g_cursor);
while ( dbms_sql.fetch_rows(g_cursor) > 0 )
loop
l_line := null;
for i in 1..l_column_count
loop
dbms_sql.column_value(g_cursor,i,l_column_value);
l_line := l_line ||p_delimited||l_column_value;
end loop;
l_line := l_line || chr(13) || chr(10); /* line terminator in windows */
utl_file.put(l_file_handle,l_line);
end loop;
utl_file.fclose(l_file_handle);
execute immediate ' alter session set nls_date_format = '''|| l_nls_values ||'''';
exception
when others then
if dbms_sql.is_open(g_cursor) then
dbms_sql.close_cursor(g_cursor);
end if;
if utl_file.is_open (l_file_handle) then
utl_file.fclose(l_file_handle);
end if;
p_status := sqlcode;
raise_application_error ( -20458,sqlerrm);
end dump_data;
end pkg_unloader;
/
Sample output
scott@10G> declare
2 l_status number;
3 begin
4 pkg_unloader.dump_data('select * from emp',
5 'DATA_PUMP_DIR',
6 'emp.dat',
7 '|',
8 l_status );
9 end;
10 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
scott@10G> host
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\179818>d:
D:\>cd D:\oracle\product\10.2.0\admin\10g\dpdump
D:\oracle\product\10.2.0\admin\10G\dpdump>type emp.dat
|7782|CLARK|MANAGER|7839|09061981000000|2450||10
|7839|KING|PRESIDENT||17111981000000|5000|0|10
|7934|MILLER|CLERK|7782|23011982000000|1300||10
|7844|TURNER|SALESMAN|7698|08091981000000|1500|0|30
|7788|SCOTT|ANALYST|7566|19041987000000|3000||20
|7698|BLAKE|MANAGER|7839|01051981000000|2850||30
|7566|JONES|MANAGER|7839|02041981000000|2975||20
|7499|ALLEN|SALESMAN|7698|20021981000000|1600|300|30
|7521|WARD|SALESMAN|7698|22021981000000|1250|500|30
|7902|FORD|ANALYST|7566|03121981000000|3000||20
|7654|MARTIN|SALESMAN|7698|28091981000000|1250|1400|30
|7369|SMITH|CLERK|7902|17121980000000|800||20
|7876|ADAMS|CLERK|7788|23051987000000|1100||20
|7900|JAMES|CLERK|7698|03121981000000|950||30
D:\oracle\product\10.2.0\admin\10G\dpdump>
Print Table Procedure
My first try about DBMS_SQL package. some thing i learnt newly today.
create or replace
procedure print_table(p_query in varchar2)
authid current_user
as
l_cursor number := dbms_sql.open_cursor;
l_sql varchar2(100) := p_query;
l_column_count number := 0;
l_desctab dbms_sql.desc_tab;
l_column_value varchar2(4000);
l_status number;
begin
dbms_sql.parse(l_cursor,l_sql,dbms_sql.native);
dbms_sql.describe_columns (l_cursor,l_column_count,l_desctab);
for i in 1..l_column_count
loop
dbms_sql.define_column (l_cursor,i,l_column_value,4000);
end loop;
l_status := dbms_sql.execute(l_cursor);
while ( dbms_sql.fetch_rows(l_cursor) > 0 )
loop
for i in 1..l_column_count
loop
dbms_sql.column_value (l_cursor,i,l_column_value);
dbms_output.put_line ( rpad(' ',5,' ')||rpad(l_desctab(i).col_name,20,'-') ||' '|| l_column_value );
end loop;
dbms_output.put_line (' ');
end loop;
dbms_sql.close_cursor(l_cursor);
end print_table;
scott@10G> exec print_table (' select * from emp where rownum <= 2 ');
EMPNO--------------- 7782
ENAME--------------- CLARK
JOB----------------- MANAGER
MGR----------------- 7839
HIREDATE------------ 09-JUN-81
SAL----------------- 2450
COMM----------------
DEPTNO-------------- 10
EMPNO--------------- 7839
ENAME--------------- KING
JOB----------------- PRESIDENT
MGR-----------------
HIREDATE------------ 17-NOV-81
SAL----------------- 5000
COMM---------------- 0
DEPTNO-------------- 10
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.04
create or replace
procedure print_table(p_query in varchar2)
authid current_user
as
l_cursor number := dbms_sql.open_cursor;
l_sql varchar2(100) := p_query;
l_column_count number := 0;
l_desctab dbms_sql.desc_tab;
l_column_value varchar2(4000);
l_status number;
begin
dbms_sql.parse(l_cursor,l_sql,dbms_sql.native);
dbms_sql.describe_columns (l_cursor,l_column_count,l_desctab);
for i in 1..l_column_count
loop
dbms_sql.define_column (l_cursor,i,l_column_value,4000);
end loop;
l_status := dbms_sql.execute(l_cursor);
while ( dbms_sql.fetch_rows(l_cursor) > 0 )
loop
for i in 1..l_column_count
loop
dbms_sql.column_value (l_cursor,i,l_column_value);
dbms_output.put_line ( rpad(' ',5,' ')||rpad(l_desctab(i).col_name,20,'-') ||' '|| l_column_value );
end loop;
dbms_output.put_line (' ');
end loop;
dbms_sql.close_cursor(l_cursor);
end print_table;
scott@10G> exec print_table (' select * from emp where rownum <= 2 ');
EMPNO--------------- 7782
ENAME--------------- CLARK
JOB----------------- MANAGER
MGR----------------- 7839
HIREDATE------------ 09-JUN-81
SAL----------------- 2450
COMM----------------
DEPTNO-------------- 10
EMPNO--------------- 7839
ENAME--------------- KING
JOB----------------- PRESIDENT
MGR-----------------
HIREDATE------------ 17-NOV-81
SAL----------------- 5000
COMM---------------- 0
DEPTNO-------------- 10
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.04
Sunday, March 14, 2010
Improved Tablespace Managment
Prior to Oracle9i Database, if the DEFAULT TABLESPACE was not specified when the user was created, it would default to the SYSTEM tablespace. If the user did not specify a tablespace explicitly while creating a segment, it was created in SYSTEM—provided the user had quota there, either explicitly granted or through the system privilege UNLIMITED TABLESPACE. Oracle9i alleviated this problem by allowing the DBA to specify a default, temporary tablespace for all users created without an explicit temporary tablespace clause
In Oracle Database 10g, you can similarly specify a default tablespace for users. During database creation Or After creation, you Can make a tablespace default by issuing.
ALTER DATABASE DEFAULT TABLESPACE tsname;
scott@10G> SELECT NAME FROM V$TABLESPACE;
NAME
------------------------------
SYSTEM
UNDOTBS1
SYSAUX
USERS_DATA
TEMP
EXAMPLE
TTS_TBL
TTS_INDX
8 rows selected.
scott@10G> ALTER DATABASE DEFAULT TABLESPACE TTS_TBL;
Database altered.
scott@10G> CREATE USER TEST_USER IDENTIFIED BY TEST_USER;
User created.
scott@10G> SELECT username, default_tablespace, temporary_tablespace
2 FROM dba_users
3 WHERE username ='TEST_USER'
4 /
USERNAME DEFAULT_TABLESPACE TEMPORARY_TABLESPACE
------------------ ------------------------------ --------------------------
TEST_USER TTS_TBL TEMP
NAME
------------------------------
SYSTEM
UNDOTBS1
SYSAUX
USERS_DATA
TEMP
EXAMPLE
TTS_TBL
TTS_INDX
8 rows selected.
scott@10G> ALTER DATABASE DEFAULT TABLESPACE TTS_TBL;
Database altered.
scott@10G> CREATE USER TEST_USER IDENTIFIED BY TEST_USER;
User created.
scott@10G> SELECT username, default_tablespace, temporary_tablespace
2 FROM dba_users
3 WHERE username ='TEST_USER'
4 /
USERNAME DEFAULT_TABLESPACE TEMPORARY_TABLESPACE
------------------ ------------------------------ --------------------------
TEST_USER TTS_TBL TEMP
If the default Tablespace is not specified during the database creation , it defaults to SYSTEM.
But how do you know which tablespace is default for existing database?
scott@10G> SELECT property_value
2 FROM database_properties
3 WHERE property_name = 'DEFAULT_PERMANENT_TABLESPACE';
PROPERTY_VALUE
---------------------------------------------------------------
NEW_TBLS
But how do you know which tablespace is default for existing database?
scott@10G> SELECT property_value
2 FROM database_properties
3 WHERE property_name = 'DEFAULT_PERMANENT_TABLESPACE';
PROPERTY_VALUE
---------------------------------------------------------------
NEW_TBLS
It is common in data warehouse environments, typically for data mart architectures, to transport tablespaces between databases. But the source and target databases must not have tablespaces with the same names. Oralce 10g offers a Convenient solution:
You can simply rename an existing tablespace using the command:
You can simply rename an existing tablespace using the command:
ALTER TABLESPACE old_name RENAME TO new_name;
scott@10G> ALTER TABLESPACE TTS_TBL RENAME TO NEW_TBLS;
Tablespace altered.
scott@10G> SELECT username, default_tablespace, temporary_tablespace
2 FROM dba_users
3 WHERE username ='TEST_USER'
4 /
USERNAME DEFAULT_TABLESPACE TEMPORARY_TABLESPACE
---------------- --------------------------- -----------------------------
TEST_USER NEW_TBLS TEMP
scott@10G> ALTER TABLESPACE TTS_TBL RENAME TO NEW_TBLS;
Tablespace altered.
scott@10G> SELECT username, default_tablespace, temporary_tablespace
2 FROM dba_users
3 WHERE username ='TEST_USER'
4 /
USERNAME DEFAULT_TABLESPACE TEMPORARY_TABLESPACE
---------------- --------------------------- -----------------------------
TEST_USER NEW_TBLS TEMP
Thursday, March 11, 2010
Index Skip Scan
Index Skip Scan were Introduced in Oracle 9i
Index Skip Scan improves index scan by non-prefix columns.
Skip scanning splits the composite index to be logically split into smaller subindexes.
The number of logical Subindexes is determined by number of distinct values of Initial column.
Skip scanning is advantage if there are few distinct values in leading column and many distinct values on non-leading key columns.
Skip scanning splits the composite index to be logically split into smaller subindexes.
The number of logical Subindexes is determined by number of distinct values of Initial column.
Skip scanning is advantage if there are few distinct values in leading column and many distinct values on non-leading key columns.
create table t as select * from all_objects;
create index t_ind on t(object_type,object_id);
exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T',estimate_percent=>100,cascade=>true,method_opt=>'for all columns size 254');
scott@10G> select object_type,count(*)
2 from T
3 group by object_type;
OBJECT_TYPE COUNT(*)
------------------- ----------
CONSUMER GROUP 2
INDEX PARTITION 446
JAVA DATA 306
RULE 7
SCHEDULE 1
SEQUENCE 227
TABLE PARTITION 298
OPERATOR 57
PROCEDURE 131
WINDOW 2
LIBRARY 152
LOB 6
PACKAGE 895
PACKAGE BODY 836
PROGRAM 12
RULE SET 26
CONTEXT 5
JAVA RESOURCE 772
TYPE BODY 176
XML SCHEMA 25
DIRECTORY 5
JOB CLASS 2
MATERIALIZED VIEW 2
TRIGGER 261
FUNCTION 294
INDEX 2143
INDEXTYPE 10
JAVA CLASS 16420
SYNONYM 20110
TABLE 1948
VIEW 3761
WINDOW GROUP 1
CLUSTER 10
EVALUATION CONTEXT 14
JOB 11
TYPE 2013
create index t_ind on t(object_type,object_id);
exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T',estimate_percent=>100,cascade=>true,method_opt=>'for all columns size 254');
scott@10G> select object_type,count(*)
2 from T
3 group by object_type;
OBJECT_TYPE COUNT(*)
------------------- ----------
CONSUMER GROUP 2
INDEX PARTITION 446
JAVA DATA 306
RULE 7
SCHEDULE 1
SEQUENCE 227
TABLE PARTITION 298
OPERATOR 57
PROCEDURE 131
WINDOW 2
LIBRARY 152
LOB 6
PACKAGE 895
PACKAGE BODY 836
PROGRAM 12
RULE SET 26
CONTEXT 5
JAVA RESOURCE 772
TYPE BODY 176
XML SCHEMA 25
DIRECTORY 5
JOB CLASS 2
MATERIALIZED VIEW 2
TRIGGER 261
FUNCTION 294
INDEX 2143
INDEXTYPE 10
JAVA CLASS 16420
SYNONYM 20110
TABLE 1948
VIEW 3761
WINDOW GROUP 1
CLUSTER 10
EVALUATION CONTEXT 14
JOB 11
TYPE 2013
36 rows selected.
So, splitting this Composite Index will result into 36 logical subindexes one for each object_type.
scott@10G> select *
2 from t
3 where object_id between 100 and 200;
100 rows selected.
Elapsed: 00:00:00.03
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100 | 9300 | 106 (1)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 100 | 9300 | 106 (1)| 00:00:02 |
|* 2 | INDEX SKIP SCAN | T_IND | 99 | | 101 (1)| 00:00:02 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID">=100 AND "OBJECT_ID"<=200)
filter("OBJECT_ID"<=200 AND "OBJECT_ID">=100)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
28 consistent gets
0 physical reads
0 redo size
3890 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
100 rows processed
2 from t
3 where object_id between 100 and 200;
100 rows selected.
Elapsed: 00:00:00.03
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100 | 9300 | 106 (1)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 100 | 9300 | 106 (1)| 00:00:02 |
|* 2 | INDEX SKIP SCAN | T_IND | 99 | | 101 (1)| 00:00:02 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID">=100 AND "OBJECT_ID"<=200)
filter("OBJECT_ID"<=200 AND "OBJECT_ID">=100)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
28 consistent gets
0 physical reads
0 redo size
3890 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
100 rows processed
Friday, March 5, 2010
Explain Plan - The Oldest Bug in Oracle
Under what conditions, autotrace and Explain plan cannot give the correct explain plan of a Sql?
create table t as select a.*,1 as id from all_objects a where rownum = 1;
create index t_ind on t(id);
alter session set sql_trace = true;
select * from t where id = 1;
insert into t select a.*,1 as id from all_objects a;
select * from t where id = 1;
alter session set sql_trace = false;
********************************************************************************
select *
from t
where id = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.04 0 2 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 2 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.01 0.04 0 4 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54 (SCOTT)
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID T (cr=2 pr=0 pw=0 time=19 us)
1 INDEX RANGE SCAN T_IND (cr=1 pr=0 pw=0 time=14 us)(object id 64947)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
1 TABLE ACCESS (FULL) OF 'T' (TABLE)
********************************************************************************
select *
from t
where id = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.10 0.11 0 1534 0 51396
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.10 0.11 0 1534 0 51396
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 54 (SCOTT)
Rows Row Source Operation
------- ---------------------------------------------------
51396 TABLE ACCESS BY INDEX ROWID T (cr=1534 pr=0 pw=0 time=102827 us)
51396 INDEX RANGE SCAN T_IND (cr=474 pr=0 pw=0 time=25 us)(object id 64947)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
51396 TABLE ACCESS (FULL) OF 'T' (TABLE)
********************************************************************************
Now how the Row Source Operation (what is called reality) differ from Execution Plan (what is called estimation). what happened here was that the Row Source Operation captured in the Trace file at the time of execution - reflects what REALLY took place as the query executed. The sequence of operation followed for the query is
1) Load a single row into the table T
2) ran the query against T - that did the hard parse using dynamic sampling sampled the table at run time and founded that using Index leads to efficient execution.
3) loaded more data with id =1 into table T
4) ran the same query from step#2 - that did soft parse and reused the plan generated back when only one row existed in the table. that leads to inefficient execution.
5) executing TKPROF with explain = / shows an entierly different execution plan. This is because explain plan always does hard parse - It dynamically sampled the table again - founded it to be large for id =1 - it would full scan. How ever the real execution of the query Index range scanned by using the plan available in shared pool.
An important note for this example - the placement of the ALTER SESSION SET SQL_TRACE=TRUE is important. As an exercise - move it to just be before the second execution of the query and you'll find the query is Hard parsed and the Row Source Operation in the Tkprof is Full table scan.
drop table t purge;
create table t as select a.*,1 as id from all_objects a where rownum = 1;
create index t_ind on t(id);
select * from t where id = 1;
insert into t select a.*,1 as id from all_objects a;
alter session set sql_trace = true;
select * from t where id = 1;
alter session set sql_trace = false;
********************************************************************************
select *
from
t where id = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 2 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.10 0.06 0 1093 0 51397
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.10 0.07 0 1095 0 51397
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54 (SCOTT)
Rows Row Source Operation
------- ---------------------------------------------------
51397 TABLE ACCESS FULL T (cr=1093 pr=0 pw=0 time=34 us)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
51397 TABLE ACCESS (FULL) OF 'T' (TABLE)
********************************************************************************
create table t as select a.*,1 as id from all_objects a where rownum = 1;
create index t_ind on t(id);
alter session set sql_trace = true;
select * from t where id = 1;
insert into t select a.*,1 as id from all_objects a;
select * from t where id = 1;
alter session set sql_trace = false;
********************************************************************************
select *
from t
where id = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.04 0 2 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 2 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.01 0.04 0 4 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54 (SCOTT)
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID T (cr=2 pr=0 pw=0 time=19 us)
1 INDEX RANGE SCAN T_IND (cr=1 pr=0 pw=0 time=14 us)(object id 64947)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
1 TABLE ACCESS (FULL) OF 'T' (TABLE)
********************************************************************************
select *
from t
where id = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.10 0.11 0 1534 0 51396
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.10 0.11 0 1534 0 51396
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 54 (SCOTT)
Rows Row Source Operation
------- ---------------------------------------------------
51396 TABLE ACCESS BY INDEX ROWID T (cr=1534 pr=0 pw=0 time=102827 us)
51396 INDEX RANGE SCAN T_IND (cr=474 pr=0 pw=0 time=25 us)(object id 64947)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
51396 TABLE ACCESS (FULL) OF 'T' (TABLE)
********************************************************************************
Now how the Row Source Operation (what is called reality) differ from Execution Plan (what is called estimation). what happened here was that the Row Source Operation captured in the Trace file at the time of execution - reflects what REALLY took place as the query executed. The sequence of operation followed for the query is
1) Load a single row into the table T
2) ran the query against T - that did the hard parse using dynamic sampling sampled the table at run time and founded that using Index leads to efficient execution.
3) loaded more data with id =1 into table T
4) ran the same query from step#2 - that did soft parse and reused the plan generated back when only one row existed in the table. that leads to inefficient execution.
5) executing TKPROF with explain = / shows an entierly different execution plan. This is because explain plan always does hard parse - It dynamically sampled the table again - founded it to be large for id =1 - it would full scan. How ever the real execution of the query Index range scanned by using the plan available in shared pool.
An important note for this example - the placement of the ALTER SESSION SET SQL_TRACE=TRUE is important. As an exercise - move it to just be before the second execution of the query and you'll find the query is Hard parsed and the Row Source Operation in the Tkprof is Full table scan.
drop table t purge;
create table t as select a.*,1 as id from all_objects a where rownum = 1;
create index t_ind on t(id);
select * from t where id = 1;
insert into t select a.*,1 as id from all_objects a;
alter session set sql_trace = true;
select * from t where id = 1;
alter session set sql_trace = false;
********************************************************************************
select *
from
t where id = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 2 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 344 0.10 0.06 0 1093 0 51397
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 346 0.10 0.07 0 1095 0 51397
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 54 (SCOTT)
Rows Row Source Operation
------- ---------------------------------------------------
51397 TABLE ACCESS FULL T (cr=1093 pr=0 pw=0 time=34 us)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
51397 TABLE ACCESS (FULL) OF 'T' (TABLE)
********************************************************************************
Subscribe to:
Posts (Atom)