Pls see this interesting note,
http://blogs.oracle.com/optimizer/2011/02/how_do_i_deal_with_a_third_party_application_that_has_embedded_hints_that_result_in_a_sub-optimal_ex.html
Pls see this interesting note,
http://blogs.oracle.com/optimizer/2011/02/how_do_i_deal_with_a_third_party_application_that_has_embedded_hints_that_result_in_a_sub-optimal_ex.html
Sometime you may want to run the rda.sh has nohup. But it take lot of input. You can create the setup.cfg using
./rda.sh -S
Again you will have to input the password if you are collecting via system.
./rda.sh -A system
enter the system password. In the same session
nohup ./rda.sh &
password what you set is valid only that session. You can run nohup from anothe r session.
you can see in the setup.cfg, newly added content like below.
#B.Multi-run collection indicator
S999END_MRC=0
#T.Password for ‘SYSTEM’
SQL_PASSWORD_SYSTEM=’(<WDR8F%S93(`’
If we could simulate the performance issue in sqlplus, consider we can fix the issue most of the time. Incase if you need oracle supports help in a query, you can build the test case like below.
SQL> DECLARE tc clob; 2 BEGIN 3 DBMS_SQLDIAG.EXPORT_SQL_TESTCASE( 4 DIRECTORY=>'DATA_PUMP_DIR', 5 SQL_ID=>'6bcwxgty705p8', 6 TESTCASE=>tc); 7 END; 8 / PL/SQL procedure successfully completed.
You need to supply sql_id and directory name. You can zip this and sent it to support. If you give exportdata to true, expdp will include table data.
This is tested in 11gR2.
Many of our sessions are waiting on ‘cursor: pin S wait on X’ in one our DB. Connecting to DB via Toad,sql developer is hanging.
Most of the sessions from toad,sql developer is waiting on, as the query all_objects during the startup.
SELECT 'X' FROM SYS.ALL_OBJECTS WHEREÂ Â Â OBJECT_NAME = :1 AND OWNER = :2 AND OBJECT_TYPE = 'TABLE'
Some kind of contention around all_objects.
To find the blocking session,
SELECT sid,last_call_et,p2raw ,to_number(substr(to_char(rawtohex(p2raw)), 1, 8), 'XXXXXXXX') sid "Blocking Sid" FROM v$session WHERE event = 'cursor: pin S wait on X' order by last_call_et;
Get the record having max last_call_et and take the correspond “Blocking Sid”. Killing the “Blocking Sid” has cleared the DB issue. Most likely this case killing sessions will take time, so kill -9 the os process.
Blocking Sid in our case is waiting on sql_id 1j4husc7c0k5u
To get the query,
SQL> select * from table(dbms_xplan.display_awr('1j4husc7c0k5u'));
SQL_ID 1j4husc7c0k5u
--------------------
select i.obj#, i.rowcnt, i.leafcnt, i.distkey, i.lblkkey, i.dblkkey,i.clufac, i.blevel,
i.analyzetime, i.samplesize, decode(i.pctthres$,null,null,mod(trunc(i.pctthres$/256),256)),
i.flags, ist.cachedblk, ist.cachehit, ist.logicalread from ind$ i, ind_stats$ ist where
i.obj# = ist.obj#(+) and i.bo#=:1 order by i.obj#
Plan hash value: 1414749717
---------------------------------------------------------------------------------------------------
| Id | Operation                    | Name             | Rows | Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------------------------------
|Â Â 0 | SELECT STATEMENTÂ Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â Â Â |Â Â Â Â Â Â |Â Â Â Â 4 (100)|Â Â Â Â Â Â Â Â Â |
|Â Â 1 |Â SORT ORDER BYÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â 4 |Â Â 400 |Â Â Â Â 4Â (25)| 00:00:01 |
|Â Â 2 |Â Â NESTED LOOPS OUTERÂ Â Â Â Â Â Â Â Â |Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â 4 |Â Â 400 |Â Â Â Â 3Â Â (0)| 00:00:01 |
|Â Â 3 |Â Â Â TABLE ACCESS CLUSTERÂ Â Â Â Â Â | IND$Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â 4 |Â Â 192 |Â Â Â Â 2Â Â (0)| 00:00:01 |
|Â Â 4 |Â Â Â Â INDEX UNIQUE SCANÂ Â Â Â Â Â Â Â | I_OBJ#Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â 1 |Â Â Â Â Â Â |Â Â Â Â 1Â Â (0)| 00:00:01 |
|Â Â 5 |Â Â Â TABLE ACCESS BY INDEX ROWID| IND_STATS$Â Â Â Â Â Â Â |Â Â Â Â 1 |Â Â Â 52 |Â Â Â Â 1Â Â (0)| 00:00:01 |
|Â Â 6 |Â Â Â Â INDEX UNIQUE SCANÂ Â Â Â Â Â Â Â | I_IND_STATS$_OBJ# |Â Â Â Â 1 |Â Â Â Â Â Â |Â Â Â Â 1Â Â (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
May be auto stats gathering happening on that time creating contention in IND$. This behaviour is documented in note#6011045.8
Refer to below link for manually creating and evolving the baseline plan.
http://www.oracle-base.com/articles/11g/SqlPlanManagement_11gR1.php
In the example given in the url above, after adding index we need to manually evolve. This helps in accepting the right plan.
But what happens if i drop the index.
SQL> drop index spm_test_tab_idx; Index dropped. SQL> EXEC DBMS_STATS.gather_table_stats(USER, 'SPM_TEST_TAB', cascade=>TRUE); PL/SQL procedure successfully completed.
SQL> SET AUTOTRACE TRACE
SQL> SELECT description
2Â FROMÂ Â spm_test_tab
3Â WHEREÂ id = 99;
Execution Plan
----------------------------------------------------------
Plan hash value: 1107868462
--------------------------------------------------------------------------------
--
| Id | Operation        | Name        | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
--
|Â Â 0 | SELECT STATEMENTÂ |Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â 1 |Â Â Â 25 |Â Â Â 13Â Â (0)| 00:00:01
|
|*Â 1 |Â TABLE ACCESS FULL| SPM_TEST_TAB |Â Â Â Â 1 |Â Â Â 25 |Â Â Â 13Â Â (0)| 00:00:01
|
--------------------------------------------------------------------------------
--
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=99)
Note
-----
- SQL plan baseline "SQL_PLAN_7qxjk7bch8h5tb65c37c8" used for this statement ==> Old base line is taken automatically
Statistics
----------------------------------------------------------
1Â recursive calls
0Â db block gets
47Â consistent gets
0Â physical reads
0Â redo size
441Â bytes sent via SQL*Net to client
416Â bytes received via SQL*Net from client
2Â SQL*Net roundtrips to/from client
0Â sorts (memory)
0Â sorts (disk)
1Â rows processed
Let me try to create that index back and see what happens,
SQL> CREATE INDEX spm_test_tab_idx ON spm_test_tab(id);
Index created.
SQL> EXEC DBMS_STATS.gather_table_stats(USER, 'SPM_TEST_TAB', cascade=>TRUE);
PL/SQL procedure successfully completed.
SQL> SELECT description
2Â FROMÂ Â spm_test_tab
3Â WHEREÂ id = 99;
Execution Plan
----------------------------------------------------------
Plan hash value: 3121206333
--------------------------------------------------------------------------------
----------------
| Id | Operation                  | Name            | Rows | Bytes | Cost (%
CPU)| Time    |
--------------------------------------------------------------------------------
----------------
|Â Â 0 | SELECT STATEMENTÂ Â Â Â Â Â Â Â Â Â Â |Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â Â 1 |Â Â Â 25 |Â Â Â Â 2
(0)| 00:00:01 |
|Â Â 1 |Â TABLE ACCESS BY INDEX ROWID| SPM_TEST_TABÂ Â Â Â |Â Â Â Â 1 |Â Â Â 25 |Â Â Â Â 2
(0)| 00:00:01 |
|*Â 2 |Â Â INDEX RANGE SCANÂ Â Â Â Â Â Â Â Â | SPM_TEST_TAB_IDX |Â Â Â Â 1 |Â Â Â Â Â Â |Â Â Â Â 1
(0)| 00:00:01 |
--------------------------------------------------------------------------------
----------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=99)
Note
-----
- SQL plan baseline "SQL_PLAN_7qxjk7bch8h5ted3324c0" used for this statement ==> Goes for the best plan
Statistics
----------------------------------------------------------
1Â recursive calls
0Â db block gets
4Â consistent gets
0Â physical reads
0Â redo size
448Â bytes sent via SQL*Net to client
416Â bytes received via SQL*Net from client
2Â SQL*Net roundtrips to/from client
0Â sorts (memory)
0Â sorts (disk)
1Â rows processed
Note: I have not evolved 2nd time after putting back the index.
Need to check how the auto Evolving of baseline works.
I generally create the profile via oem. The below link explains how to create via command line,
http://www.oracle-base.com/articles/10g/AutomaticSQLTuning10g.php
We have a DB which connects to other DB via LDAP connection. We had an issue where db link to another db server is slow.
I have limited expertise on LDAP. This is how i solved the issue.
select * from dual@db_link;
it’s slow first time. In the same session if we run it again, it’s fast.
Opened a SR.Got all the trace files but no update.
I enabled tnsping trace using below command
#TNSPING.TRACE_LEVEL = 16 #TNSPING.TRACE_DIRECTORY=/tmp
It didn’t have time info. So enabled the client and server level trace.
#trace_level_server=16 #trace_level_client=16 #trace_directory_server=/tmp #trace_directory_client=/tmp #trace_file_client=cli1 #trace_file_server=srv1 #trace_unique_client=true
in the trace
[04-AUG-2010 05:20:19:035] nnflilc:Â Opening sync conn to server1.domain.com:123 [04-AUG-2010 05:21:33:947] nnflilc:Â Â ldap_open failed ld:0
almost a minute it waits on server1, then it goes to server 2 and connects
[04-AUG-2010 05:21:33:954] nnflilc:Â Opening sync conn to server2.domain.com:123 [04-AUG-2010 05:21:33:979] nnflalc: entry [04-AUG-2010 05:21:34:009] nnflalc:Â Â Â Â bind call returns 0
This gives the clue that server1 oid is having issue. So we changed the ldap.ora look up
DIRECTORY_SERVERS= (server1.domain.com:123:636,server2.domain.com:123:636)
to
DIRECTORY_SERVERS= (server2.domain.com:123:636,server1.domain.com:123:636)
command to start and stop oid.
oidmon start oidctl server=oidldapd1 instance=1 configset=1 start oidctl server=oidrepld1 instance=1 flags="-h server1 -p 389" start
stop
oidctl server=oidldapd1 instance=1 configset=1 stop;sleep 10 oidctl server=oidrepld1 instance=1 stop;sleep 10 oidmon stop
In sqlt.zip there is a script called coe_xfr_sql_profile.sql which will help in generating the sql_profile from other_xml of v$sql_plan and output in executable format. This helps in moving the plan across the environment and also before creating profile helps you in editing the hints.
SQL> @/tmp/coe_xfr_sql_profile.sql Parameter 1: SQL_ID (required) Enter value for 1: bcmu3by7zdb03 Parameter 2: PLAN_HASH_VALUE (required) Enter value for 2: 2415307779 Values passed: ~~~~~~~~~~~~~ SQL_IDÂ Â Â Â Â Â Â Â : "bcmu3by7zdb03" PLAN_HASH_VALUE: "2415307779" Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bit Production With the Partitioning, Data Mining and Real Application Testing options
New diagonistic tool is introduced in 11g. Using which we can gather all the information relevant to an issue and upload to oracle or investigate by yourself.
adrci is executable in $ORACLE_HOME/bin location
$ adrci ADRCI: Release 11.1.0.7.0 - Production on Mon Jul 26 04:08:33 2010 Copyright (c) 1982, 2007, Oracle. All rights reserved. ADR base = "/opt/apps/oracle" adrci> adrci> show home ADR Homes: diag/rdbms/db1 diag/rdbms/db2 diag/rdbms/db3 diag/rdbms/db4 diag/tnslsnr/hostname/listener_bor3rep adrci> set homepath diag/rdbms/db1 adrci> show problem ==> this will report the problem recently poped up in the db. ************************************************************************* PROBLEM_ID          PROBLEM_KEY                                                LAST_INCIDENT       LASTINC_TIME -------------------- ----------------------------------------------------------- -------------------- ---------------------------------------- 3                   ORA 7445 [_memset()+120]                                   32093               2010-07-25 18:01:06.962092 -04:00 4                   ORA 7445 [_doprnt()+44]                                    32077               2010-07-25 18:01:03.642031 -04:00 2                   ORA 4030                                                   32270               2010-07-25 18:01:00.837604 -04:00 1                   ORA 7445 [ioc_pin_shared_executable_object()+952]          28842               2010-06-05 22:39:34.757161 -04:00 4 rows fetched If you want to diagonise 4030 error, then adrci> ips pack problem 2 in /tmp Generated package 3 in file /tmp/ORA4030_20100726041042_COM_1.zip, mode complete
Upload the trace file to oracle or use it for investigation. Has all the information relevant to 4030 error.
When the primary archive location fills, there is an option of writing to alternate archivelog location. These parameter needs to be set.
log_archive_dest_1='LOCATION=use_db_recovery_file_dest NOREOPEN ALTERNATE=LOG_ARCHIVE_DEST_2' log_archive_dest_2='LOCATION=/other_destination_for_archiving' log_archive_dest_state_1='enable' log_archive_dest_state_2='alternate'
You could use the following to revert back after failover:
alter system set log_archive_dest_state_1 = enable; alter system set log_archive_dest_state_2 = alternate;
But make note of below restriction when setting this.Metalink#369120.1
” The REOPEN attribute takes precedence over the ALTERNATE attribute. The alternate destination is
used only if one of the following is true:
- The NOREOPEN attribute is specified.
- A value of zero (0) is specified for the REOPEN attribute.
- A nonzero REOPEN attribute and a nonzero MAX_FAILURE count have been exceeded. ”
It’s preferable to set NOREOPEN to the default location and enable this option.
We had an outage, where pga eating up all the memory crashing the vcs. We temporarily solved the issue by moving to shared server and reducing the pga size.
Came across some of the suggestion to restrict pga,
1. Private_sga in MTS
2. 10261 event
10261, 00000, "Limit the size of the PGA heap"
// *Cause: the limit is one kilobyte times the level of the event. If the
// pga grows bigger than this signal an internal error.
to set a session to 100mb
| Â | alter system set events '10261 trace name context forever, level 100000'; |
useful note is found in
http://dioncho.wordpress.com/2010/06/14/rapid-pga-size-increase/
for setting multiple events in spfile, you can use below command
ALTER SYSTEM SET event='10261 trace name context forever, level 15000000','600 trace name heapdump, level 0x20000001' COMMENT='pga issue' SCOPE=SPFILE;
for resetting use,
2: |
ALTER SYSTEM RESET EVENT SCOPE=SPFILE SID='*' ; |
Note: Have tried setting 10261 event in shared server db, but process didn't crash once reached the limit.
3. DBMS_SESSION.FREE_UNUSED_USER_MEMORY
convert this post to pdf.
When one of the db got upgraded from 10202 to 10205, we found out one of the query is very slow. Didn’t taken the export of stats before upgrade. This is one way we forced a profile to this query.
declare
pln_sql_id varchar2(20) :='fathgmks3vb1g';
pln_plan_hash_value number := 3396554601;
orig_sql_id varchar2(20) := 'fathgmks3vb1g';
new_prof_name varchar2(20) := 'SQL_PROFILE_1';
ar_profile_hints sys.sqlprof_attr;
cl_sql_text clob;
begin
select extractvalue(value(d), '/hint') as outline_hints
bulk collect into ar_profile_hints
from xmltable('/*/outline_data/hint'
passing (select xmltype(other_xml) as xmlval from dba_hist_sql_plan
where sql_id = pln_sql_id and plan_hash_value = pln_plan_hash_value
and other_xml is not null)) d;
select sql_text into cl_sql_text
from dba_hist_sqltext where sql_id = orig_sql_id;
dbms_sqltune.import_sql_profile(
sql_text => cl_sql_text,
profile => ar_profile_hints,
name => new_prof_name,
force_match => true);
end;
/
The below script can be used to see what’s the access path for a hash_value. This can be seen when you create outln and query ol_hint$
select
substr(extractvalue(value(d), '/hint'), 1, 100) as outline_hints
from
xmltable('/*/outline_data/hint'
passing (
select
xmltype(other_xml) as xmlval
from
v$sql_plan
where
hash_value = 2378699969
and child_number = 0
and other_xml is not null
)
) d;
You need to drop any sql_profile created before forcing a plan.
exec DBMS_SQLTUNE.DROP_SQL_PROFILE(name => 'SYS_SQLPROF_014a4a1e346a8004', ignore => TRUE);
Steps for export and importing the db stats. This helps when you change the stats gathering approach.
exec dbms_stats.create_stat_table(ownname => ‘SYS’, stattab => ‘db_stat’, tblspace => ‘SYSTEM’)
exec dbms_stats.export_database_stats(stattab => ‘db_stat’,statown => ‘SYS’)
exec dbms_stats.import_database_stats(stattab => ‘db_stat’,statown => ‘SYS’)
if you have used OEM, then you should have used sql tuning advisor. Sometime if the plan is very large you will not be able to implement the profile. You will get message like,
“There was a problem creating the SQL Profile setString can only process strings of less than 32766 chararacters”
Instead of implementing via OEM, use the below script to force the profile. But remember the tuning name what you have generated.
begin dbms_output.put_line( dbms_sqltune.accept_sql_profile( task_name => 'sql_tuning_xyz', name => 'manual_forcing', replace => true, force_match => true ) ); end; /
From 10g there is a change in No_Invalidate parameter of dbms_stats. Default value of No_Invalidate in 10g is dbms_stats.Auto_Invalidate. Means the cursor will remain valid for 5 hrs after the stats gathering. This is to avoid spike in cpu and othe resources due to hard parsing. 5 hrs time limit is governed by underscore parameter “_optimizer_invalidation_period”
delete from adv_temp.recs_type_966 where 1 = 1 and exists ( select * from adv_master.RECS_TYPE_966_VIEW r where r.plot_fk in (-1,5419,5420) and r.plot_fk between 5419 and 5420 and r.p019 = recs_type_966.p019 and r.p027 = recs_type_966.p027 and r.f001 = recs_type_966.f001 );
Subquery got a view. The session which is executing was hanging, interestingly it was hanging on ‘SQL*Net message from client’. To me it looked like a merging issue. So i recommeded to include rownum >0 to the subquery. But it was rejected as this is a vendor code and we don’t have any control on this.
Meanwhile, we tried various options like changing cursor_sharing=exact, increasing pga_aggregate_target etc., But it didn’t work out.
When i insert a rule hint to the subquery, it worked fine.
delete from adv_temp.recs_type_966 where 1 = 1 and exists ( select /*+rule*/ * from adv_master.RECS_TYPE_966_VIEW r where r.plot_fk in (-1,5419,5420) and r.plot_fk between 5419 and 5420 and r.p019 = recs_type_966.p019 and r.p027 = recs_type_966.p027 and r.f001 = recs_type_966.f001 );
But again this not acceptable, since we can’t change the code.
Luckily we got the alternate solutions. We introduced the underscore parameter “_unnest_subquery”=false. It worked great.
It’s a dynamic parameter and we set it as spfile=both;
The batch program went fine without any issues.
Visitors Count
satheeshb@10.2.0.2.0> drop table t;
Table dropped.
satheeshb@10.2.0.2.0> create table t ( pk1 int,pk2 int, nk1 int not null,
nk2 int not null, primary key (pk1,pk2));
Table created.
satheeshb@10.2.0.2.0> create index tx on t(pk1,nk1,pk2,nk2);
Index created.
satheeshb@10.2.0.2.0> insert into t values (1,1,2,2);
1 row created.
satheeshb@10.2.0.2.0> insert into t values (2,1,1,1);
1 row created.
satheeshb@10.2.0.2.0> analyze table t compute statistics
2 ;
Table analyzed.
satheeshb@10.2.0.2.0> set autotrace on explain
satheeshb@10.2.0.2.0> select nk1, nk2, pk1, pk2, count(*) a_count
2 from t
3 group by nk1,nk2,pk1,pk2;
NK1 NK2 PK1 PK2 A_COUNT
---------- ---------- ---------- ---------- ----------
2 2 1 1 1
1 1 2 1 1
Execution Plan
----------------------------------------------------------
Plan hash value: 2968033836
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 16 | 1 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT| | 2 | 16 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | TX | 2 | 16 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------
So if you want the rows to be retrieve, the only way is actually to use “ORDER BY”. You have to bear the cost of sorting anyway.
Visitors Count
Usage will be,
satheeshb@10.2.0.2.0> exec dbms_stats.set_param('trace','3166');
PL/SQL procedure successfully completed.
satheeshb@10.2.0.2.0> exec dbms_stats.gather_table_stats(user,'T3',
CASCADE=>TRUE);
PL/SQL procedure successfully completed.
This will generate a trace file in udump area. This trace file will clearly shows what happens behind the scene during dbms_stats.
Various levels of set_param,
1 = use dbms_output.put_line instead of writing into trace file 2 = enable dbms_stat trace only at session level 4 = trace table stats 8 = trace index stats 16 = trace column stats 32 = trace auto stats 64 = trace scaling 128 = dump backtrace on error 256 = dubious stats detection 512 = auto stats job 1024 = parallel execution tracing 2048 = print query before execution 4096 = partition prune tracing 8192 = trace stat differences Therefore, TRACE 3166 = 2048 + 1024 + 64 + 16 + 8 + 4 + 2.
Visitors Count
Database is in Archivelog Mode. Table "T" in Logging mode.
satheeshb@10.2.0.2.0> insert /*+append*/ into t select * from t3;
4772728 rows created.
Statistics
----------------------------------------------------------
3726 recursive calls
10150 db block gets
8933 consistent gets
7729 physical reads
64240476 redo size
658 bytes sent via SQL*Net to client
573 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
11 sorts (memory)
0 sorts (disk)
4772728 rows processed
Note: That quite a lot of redo generated.
satheeshb@10.2.0.2.0> commit;
Commit complete.
satheeshb@10.2.0.2.0> truncate table t;
Table truncated.
satheeshb@10.2.0.2.0> insert /*+append*/ into t nologging select * from t3;
4772728 rows created.
Statistics
----------------------------------------------------------
4606 recursive calls
10152 db block gets
9078 consistent gets
7745 physical reads
64289508 redo size
663 bytes sent via SQL*Net to client
583 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
37 sorts (memory)
0 sorts (disk)
4772728 rows processed
Note: Though the nologging is given in query level there is no impact
on redo generation. This is because the db is in Archivelog mode.
If the db was running in NoArchivelog mode, the above insert
statement would have generated much lesser redo.
satheeshb@10.2.0.2.0> commit; Commit complete. satheeshb@10.2.0.2.0> truncate table t; Table truncated.
Now let us convert the table “T” to Nologging. This is to ensure that some responsible person with “ALTER” privillege can take the decision of enabling Nologging in Archivelog DB.
satheeshb@10.2.0.2.0> alter table t nologging;
Table altered.
satheeshb@10.2.0.2.0> insert /*+append*/ into t select * from t3;
4772728 rows created.
Statistics
----------------------------------------------------------
4201 recursive calls
10155 db block gets
8991 consistent gets
7729 physical reads
241244 redo size
662 bytes sent via SQL*Net to client
574 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
21 sorts (memory)
0 sorts (disk)
4772728 rows processed
Note: There is huge difference in the “Redo size” generation. This extra check is required, as Nologging in Archivelog will invalidate the backup.
Visitors Count
satheeshb@10.2.0.2.0> declare
2 num number := 0;
3 --
4 cursor c1 is
5 select * from t where n = num;
6 begin
7 dbms_session.session_trace_enable(true,false);
8 open c1;
9 close c1;
10
11 end;
12 /
PL/SQL procedure successfully completed.
From tkprof output, you get the correct plan even without executing the query.
SELECT *
FROM
T WHERE N = :B1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.05 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.01 0.05 0 0 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 56 (recursive depth: 1)
Rows Row Source Operation
------- ---------------------------------------------------
0 TABLE ACCESS FULL T (cr=0 pr=0 pw=0 time=5 us)
Visitors Count
Satheeshb> create or replace view dynamic_plan_table
2 as
3 select
4 rawtohex(address) || '_' || child_number statement_id,
5 sysdate timestamp, operation, options, object_node,
6 object_owner, object_name, 0 object_instance,
7 optimizer, search_columns, id, parent_id, position,
8 cost, cardinality, bytes, other_tag, partition_start,
9 partition_stop, partition_id, other, distribution,
10 cpu_cost, io_cost, temp_space, access_predicates,
11 filter_predicates
12 from v$sql_plan;
View created.
Now, you can query any plan from the database with a single query:
Satheeshb> select plan_table_output
2 from TABLE( dbms_xplan.display
3 ( 'dynamic_plan_table',
4 (select rawtohex(address)||'_'||child_number x
5 from v$sql
6 where sql_text='select * from t t1 where object_id > 32000' ),
7 'serial' ) )
8 /
PLAN_TABLE_OUTPUT
------------------------------------------------------------------
| Id | Operation | Name|Rows| Bytes |Cst(%CPU)|
------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | TABLE ACCESS BY INDEX ROWID| T |291 | 27936 | 25 (0)|
|* 2 | INDEX RANGE SCAN | T_PK|291 | | 2 (0)|
------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID">32000)
13 rows selected.
Visitors Count
Please find a small test case to show superior power of cbo when cpu costing is enabled.
Step 1:
~~~~~~
Delete the system statistics if any
SQL> exec dbms_stats.delete_system_stats;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.09
Step 2:
~~~~~~~
Drop, create and index the table T1. Gather table level statistics.
SQL> drop table t1;
Table dropped.
Elapsed: 00:00:00.31
SQL> create table t1 as
2 select
3 trunc(sysdate-1) + rownum/1440 d1,
4 rownum n1,
5 rpad('x',100) padding
6 from
7 all_objects
8 where
9 rownum <= 3000
10 ;
Table created.
Elapsed: 00:00:00.18
SQL> alter table t1
2 add constraint t1_pk primary key (d1,n1)
3 using index (create index t1_pk on t1(d1,n1))
4 ;
Table altered.
Elapsed: 00:00:00.13
SQL> execute dbms_stats.gather_table_stats(user,'t1',cascade=>true);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.31
Step 3:
~~~~~~~
I am firing a query again the table t1, 10000 times. Please note the timing of the executing. It is 32 seconds. I have re-executed it, just to make sure second time it takes the block from cache.
SQL> declare 2 i binary_integer :=0; 3 lv varchar2(100); 4 begin 5 for i in 1..10000 loop 6 select /*+ index(t1) */ 7 padding 8 into lv 9 from t1 10 where d1 >= trunc(sysdate) 11 and n1 = 2800; 12 -- i := i+1; 13 end loop; 14 end; 15 / PL/SQL procedure successfully completed. Elapsed: 00:00:32.07 SQL> / PL/SQL procedure successfully completed. Elapsed: 00:00:32.00
Step 4:
~~~~~~
I am gathering system statistics. It also can be done using dbms_stats.gather_system_stats. Please note the flushing of shared pool. This is required to invalidate any cursor already in the shared pool. So that it generate new cursor based on cpu costing. This flushing of shared pool is not required in 10g.
SQL> begin
2 dbms_stats.set_system_stats('CPUSPEED',500);
3 dbms_stats.set_system_stats('SREADTIM',5.0);
4 dbms_stats.set_system_stats('MREADTIM',30.0);
5 dbms_stats.set_system_stats('MBRC',12);
6 END;
7 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.03
SQL> alter system flush shared_pool;
System altered.
Step 5:
~~~~~
I am re-executing the plsql block executing in the step 3. Now this time it takes just 9 seconds. So cpu costing has made a huge difference in the time.
SQL> declare 2 i binary_integer :=0; 3 lv varchar2(100); 4 begin 5 for i in 1..10000 loop 6 select /*+ index(t1) */ 7 padding 8 into lv 9 from t1 10 where d1 >= trunc(sysdate) 11 and n1 = 2800; 12 -- i := i+1; 13 end loop; 14 end; 15 / PL/SQL procedure successfully completed. Elapsed: 00:00:08.69 SQL> / PL/SQL procedure successfully completed. Elapsed: 00:00:08.75
Step 6:
~~~~~~
Though the code and explain plan for the plsql block on step 3 and step 5 is same, the cpu costing has made the difference by rearranging the predicates. ( you need to have “_pred_move_arround” enabled and “ordered_predicate” hint shouldn’t be used) I have used dbms_xplan to find out the predicate order for this query.
with cpu costing enabled,Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."D1">=TRUNC(SYSDATE@!) AND "T1"."N1"=2800)
filter("T1"."N1"=2800 AND "T1"."D1">=TRUNC(SYSDATE@!))
With cpu costing disabled,
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."D1">=TRUNC(SYSDATE@!) AND "T1"."N1"=2800)
filter("T1"."D1">=TRUNC(SYSDATE@!) AND "T1"."N1"=2800)
Note: cpu costing is off
Please note the filter value, when cpu costing disabled,
Trunc function is executed first on 3000 rows and to the output N1=2800 condition is added. Whereas when cpu costing is enabled ,N1=2800 is executed first on 3000 rows and to the output trunc function is added. It means trunc function is added to fewer than 3000 rows. Thus less load on CPU and increase in response time.How did cpu costing is making such a move?
A new code path comes into play when cpu costing is enabled. Along with selectivity of each predicate optimizer also checks, for each action how much cpu unit is required. There by without changing the execution plan it executes the query faster.Also please note, when you enabled cpu costing, you don’t have to play around with db_file_multiblock_read_count and optimizer_index* parameters. As optimizer silently changes this value based on hardware capacity.
Addendum 15th october 2006
Also please note, when you enabled cpu costing, you don’t have to play around with db_file_multiblock_read_count . As optimizer silently changes this value based on hardware capacity. optimizer_index_cost_adj is still used in exact manner when system statistics is enabled. Not sure about the other parameter optimizer_index_caching.
dbmrc will be silently set as adjusted dbmrc. But regarding optimizer_index* need to check whether system stats nullifies this.
Visitors Count