Archive for the ‘Oracle Performance’ Category

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

convert this post to pdf.

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(`’

convert this post to pdf.

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.

convert this post to pdf.

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

convert this post to pdf.

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.

convert this post to pdf.

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

convert this post to pdf.

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
convert this post to pdf.

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
convert this post to pdf.

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.

convert this post to pdf.

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.

convert this post to pdf.

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);
convert this post to pdf.

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’)

convert this post to pdf.

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;
/
convert this post to pdf.

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”

convert this post to pdf.
In one of our DB, a delete statement was hanging.

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


convert this post to pdf.

Only “ORDER BY” to sort

If you want to retreive rows in some order use “ORDER BY”. Though “GROUP BY”, forcing index might seem to return in sorted order, but it is not often.
“GROUP BY” doesn’t do character sorting, it actually does Binary Sort. There are many factors like partitioning, table organisation, optimizer_mode, DOP, indexes etc., affects the order by rows retrieved.
I remember seeing a note in metalink, where in future, index may not be stored in sorted order. This may not seems to be likely. However, the rows retrieved using index scan may not be in sorted order. Atleast with current Index full scan and Range scan it is not true.

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


convert this post to pdf.

Dbms_Stats.Set_Param

There is an unsupported way to trace gathering statistics using dbms_stats.

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


convert this post to pdf.

Posted by Borndba on April 4, 2009 at 12:14 am under Oracle, Oracle Performance.
Tags: ,
Comments Off.

Archivelog Nologging

There is a shuttle difference when Nologging is used with Archivelog database. Nologging should be given in Table level NOT in Query level. This is to tell oracle that you are serious in setting the Nologging option.

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


convert this post to pdf.

Posted by Borndba on April 4, 2009 at 12:13 am under Oracle, Oracle Performance.
Tags: ,
Comments Off.

Generating plan without executing

Generating explain plan using autotrace or dbms_xplain may not be correct when bind variable peeking comes to play. There is an interesting way to get the correct plan without executing the statement. Please see the below command.

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

class="statcounter">

href=”http://www.statcounter.com/blogger/”
target=”_blank”> src="http://c.statcounter.com/4628332/0/06d2759c/0/"
alt="blogspot visitor" >


convert this post to pdf.

Posted by Borndba on April 4, 2009 at 12:04 am under Oracle, Oracle Performance.
Tags: ,
Comments Off.

Explain Plan output from v$sql_plan

 

If you want to get the explain plan output from v$ table you can use the below query.

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


convert this post to pdf.

Posted by Borndba on April 4, 2009 at 12:01 am under Oracle, Oracle Performance.
Tags: ,
Comments Off.

Cpu_Costing

If cpu costing is not enabled, optimizer costs both single block read and multiple block reads equally. This results in in-efficient path. Over the years CBO costing methods evolved in these ways,
Oracle 7, cost is calculated based on simple io request.
Oracle 8i, cbo accounted size and time of io request.
Oracle 9i, cbo accounted cpu costs,size and time of io request.
From 10g, cbo accounted caching,cpu costs,size and time of io request. But caching effect is not enabled by default in 10g. You need to enable “_cache_stats_monitor” to account caching by CBO.

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


convert this post to pdf.

Posted by Borndba on April 3, 2009 at 11:56 pm under Oracle, Oracle Performance.
Tags: ,
Comments Off.