For DBA

Oracle Site for DBA

  • Enter your email address to follow this blog and receive notifications of new posts by email.

    Join 16 other followers

  • Blog Stats

    • 23,921 hits
  • Top Clicks

  • Top Rated

  • Cluster

  • NewsCast

    Aggregated by ITNewsCast.com

Archive for the ‘Uncategorized’ Category

Profile Baselines Patches

Posted by Sumit on March 2, 2013

Whats the difference …

I should have written this one earlier but better late than never.

So, lots of DBA’s might me thinking, why oracle has 3 ways to accomplish same task (plan stability).

This post is intended to reflect the way profiles/patches and baselines work and also the same old question “why oracle is not picking my baseline”. (of-course there could be bug but not in every case).

To start with, all of them uses the same common table (sqlobj$ and sqlobj$auxdata) in their view definition. (sql$text and sql$ are used just for matching the signature of the query).

Lets target these table one by one  to understand what they store and how oracle uses this information.

1. SQLOBJ$

Other than the signature and type (profile/baseline/profile), this table necessarily stores the state of the underlying object using the column flags.

Oracle matches the signature on this table with exact_matching (or force_matching of v$sql depending on case ) with signature of this column to extract the eligible candidates (profiles/baselines/patches).

Object_type  1 corresponds to profiles, type 2 to baselines and type 3 to patches. Then oracle checks the flags value to filter out them.

  1. flag 0,1  corresponds to state (enabled/disabled) in case of profiles/patches.
  2. flag value in case of  baselines corresponds to enabled,accepted,fixed,reproduced, auto purged.

The name column corresponds to the name of the profile/baseline/patch.

Plan_id is always 0 in case of profile/patches and corresponds to plan_hash_2(other_xml of v$sql) in case of baselines.

This brings us back to our original question: why baselines are not getting used and whats the difference between plan_hash and plan_hash_2.

In general, we can refer any execution plan with plan_hash, however in many cases oracle generates different plan_hash if its using temp tables (whose name can differ).

so oracle is using plan_hash_2 which is independent of the intermediate objects name conventions which oracle creates for himself for executing a query.

In case of baseline, oracle matches plan_hash_2 with plan_id and if they differ, oracle refuses to use them.

As mentioned earlier, in case of profiles and patches, plan_id is always 0 which means oracle does not match the plan_hash_2.

How does it affects the working of profiles/patches and baselines:-

In case of profiles/patches, since oracle never compares the plan_hash_2, it uses the hints (which are stored in sqlobj$data table), to come up with an execution plan.

In case of baselines, oracle uses the hints to come up with the execution plan and compares the plan_hash_2 of that plan with already stored plan_id. If it matches, oracle uses the plan else it simply ignores it.

The important point here to be noted is oracle uses same sqlobj$data table to store the hints for all the 3 approaches. It just that how oracle interpret these ones, change the behavior.

That raises another very interesting question. If oracle himself is capturing the hints for baselines, then why plan_id and plan_hash_2 differs.

Lets say, you want to scan a particular table using parallel clause and then you can to use this baseline to link to the query not using parallel hint.

select /*+ full(a) parallel (a 4) */ * from emp  –> select * from emp

Well you can do so by using linkbaseline.sql .

Oracle will link the plan with the handle but will not use it in case you try to run the latter.

Reason:- Oracle never captures parallel hint. ( I will demonstrate how to overcome this using patch in my next post)

So there you are. While generating the plan, oracle stored the plan_id but when oracle tried to reproduce the same using the hints, it can’t.

And that’s why your baseline won’t get used.

2. SQLOBJ$AUXDATA

As name suggests this table captures auxiliary information like created by, created date, last modified date etc.

In case of baselines, it also stores buffer_gets/disk_reads etc, since you need this info to evolve or accept a better plan.

In case of profile/patches, these fields are marked as null.

It also captures, the task_id etc if case you are not loading plans manually.

3.  SQLOBJ$DATA

This is the table where oracle stores the hint (comp_data) for the profiles/baselines and patches.

This point is worth noting that oracle captures different set of hints for profile/baselines/patches.

For e.g. if you have an existing profile(or patch) in your database, and capture is set to true, oracle will create a baseline on top of it.

And you may have notice, that execution plan reports both profile and baseline getting used.

How oracle is working ? Is it picking profile or baseline?

oracle is basically using the profile in this case. Once oracle uses the hints stored in profile and come up with execution plan, it compares the plan_hash_2 with plan-id for the baseline.

Since baseline is sitting on top of profile, it will match and oracle will report both profile and baselines are getting used.

Basically in this case, baseline hints will be subset of profile hints.

What will happen if you drop profile? Oracle may stop using baseline. As I have mentioned earlier, oracle captures different set of hints for profiles and baselines.

If you drop a profile, chances are oracle may not able to regenerate the plan using the hints stored for baseline as it was just a subset.

Posted in Uncategorized | Tagged: , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a Comment »

DBA_SNAPSHOTS Vs. DBA_MVIEWS

Posted by Sumit on April 14, 2012

Couple of my last posts were solely based on oracle profiles and baselines.

This time, I thought of putting some stuff related to Mviews.

There are various blogs which explains the working on Mviews refresh and usage of SYS.SNAP$ and SYS.MLOG$.

Before proceeding further, I would like to echo, that you should have basic understanding on mviews and fast refreshes.

Coming back to the main topic,

1. what is the difference between a snapshot and a mview.

2. Are these same, and If yes, why they coexisted.

3. If not, then what is the difference.

Snapshot & Mviews

The term snapshots and mviews are used interchangeably. Various blogs will report that these are the same things with no difference.

If there is no difference, then why do we have dba_snapshots and dba_mviews in the database.

And if both these mviews co-exists , just for “backward compatibility”, then why their definitions are different. Why not just a synonym.

I stumble on these questions during one of my production issue.

As I dig further,I found that there is a difference, which in Newton’s language should be called as “Frame of Reference”.

SNAPSHOTS

Consider a situation, where multiple snapshot sites are pulling data from one master site.

Think if you are sitting right at top of the box and can see the data flowing downstream to the snapshot sites.

So, the master site is your frame of reference and you use the term snapshot.

MVIEWS

Imagine you are sitting at the snapshot site and you can see the data flowing into the site from master sites.

Your frame of refernce is snapshot site and you use the term mview.

What does it means to oracle

Lets consider a real time example.

Imagine if two different snapshot sites are performing fast refresh from a master site.

The Mlog at the master site can not purge the data, unless all the snapshot sites have refreshed.

It reads OLDEST_PK and YOUNGEST from sys.mlog$ to decide which data it can purge.


select OLDEST_PK,SYSDATE,YOUNGEST from sys.mlog$ where master='TEST';

OLDEST_PK                 SYSDATE             YOUNGEST
-------------------- -------------------- --------------------
14-apr-2012 11:55:01 14-apr-2012 12:00:50 14-apr-2012 12:00:42

As we can see, it can safely purge data before 14-apr-2012 11:55:01.

Lets make the situation complex.

What if these two databases are running on ten different countries in ten different timezones.

What will happen if Master site happens to be in US (UTC timezone) and one client site in China(CST-8) and other in US(PST8PDT).

As we know, China’s time is ahead of US.

For E.g

Lets say, currently at 4pm china time (1am US time), CHINA1 gets refreshed from master site.

After that, another snapshot site US2 gets refreshed.

In case Master site uses Snapshot Sites local sysdate to record when they got last refresh, then CHINA2 will report 4PM which is ahead of sysdate of master site.

Clearly, this can’t be the case. SYSDATE has to be ahead of LAST_REFRESH.

Therefore, whenever a site gets refreshed, master updates oldest_pk and youngest with local sysdate(timezone).

Or in short, SYS.mlog$ will report time from master site timezone.

Now, lets say, you logged into China database.

You wanted to check last_refresh date of the mview.

Now, in this case if oracle uses Master Site date, then it will show you that mview got refreshed 13hours before. This is not correct.

Therefore Oracle created 2 Views

1. DBA_SNAPSHOTS which gets last_refresh from sys.snap_reftime$ which reports date of master site.

2. DBA_MVIEWS which gets current_snapshot from sys.sum$ which reports sysdate from local database.

Therefore, if you are at master site and you wanted to check which mview got refreshed at what time, you should use dba_snapshpot_logs (sys.slog$) which shows last_refresh with respect to master site.

In case, you are at snapshot site, you should use dba_mviews , which will show you last_refresh with respect to local sysdate.

TestCase

Master site timezone (UTC)

Snapshot Site (CST-8)


MASTER>>select sysdate from dual;
SYSDATE
--------------------
14-apr-2012 04:36:01

CLIENT>>select sysdate from dual;
SYSDATE
--------------------
14-apr-2012 12:36:20

MASTER>>select site.SNAPSHOT_SITE,logs.CURRENT_SNAPSHOTS,sysdate from dba_registered_snapshots site,dba_snapshot_logs logs where site.snapshot_id=logs.snapshot_id and MASTER='TEST' ORDER BY 3 DESC;
SNAPSHOT_SITE         CURRENT_SNAPSHOTS                SYSDATE
-------------------- -------------------         --------------------
CHINA1                14-apr-2012 04:36:01         14-apr-2012 04:41:33
US1                   14-apr-2012 04:36:21         14-apr-2012 04:41:33

Lets check the behavior on snapshot site, first using dba_snapshot view which should report last_refresh wrt master_site

CHINA1>>select name,sysdate,last_refresh from dba_snapshots where name='TEST';
     NAME                       SYSDATE             LAST_REFRESH
 -------------------    --------------------     --------------------
   TEST                    14-apr-2012 12:38:34  14-apr-2012 04:36:01

Now, if we query the same thing from dba_mviews this should report wrt local timezone.

CHINA1>>select last_refresh_date,sysdate from dba_mviews where mview_name='TEST';

LAST_REFRESH_DATE           SYSDATE
 --------------------     --------------------
 14-apr-2012 12:36:02     14-apr-2012 12:39:59

In the nutshell

sys.slog$ and sys.snap_reftime$ shows last_refreshed_date as per master_site timezone and therefore dba_snapshots and dba_snapshot_logs reports time as per master_site sysdate.

sys.sum$ updates current_snapshot as per snapshot site time and therefore dba_mviews reports last_refresh_date as of snapshot site time.

Posted in Mview, Uncategorized | Tagged: , , , , , , , , , , , , , , , , , , , , , | 4 Comments »

SPM and Profiles –Part 3

Posted by Sumit on January 23, 2012

Fix for  ”My Explain plan and Execution plan are different”

You might think , that i got possessed with baselines and profiles but I like exploring them.

The deeper I explore, the more fun it is.

In the last post, I had covered how to convert profiles baselines into profiles.

Taking a step further this time, I tried to sync my explain plan with execution plan.

A bit of history:-

Some days back, I ran into issue where explain plan was looking very much optimal but when I executed the query, it was picking different plan.

So, i thought why not get a way to force the plan of explain plan during execution.

In other words, why not sync my explain plan and execution plan.

So, i started exploring plan_table and voila….there it was. My favorite column other_xml.

By now, you must have realized, that oracle stores all the hints and some other stuff like (plan_hash2->This i will explain in some other post) in this column. When you use dbms_xplan, oracle parses this column and print in readable format.

I too extracted the info in my desired format from this column and create a script(xplanprofile.sql) to generate profile.

xplanprofile.sql

Session1> explain plan for select * from master_log where task_id=:b1;
Session1>@xplanprofile
enter original sql_id:- 9ghy678ujy345
enter bad plan hash value to be tuned :- 3709384
'===================OUTPUT========================='

declare
ar_profile_hints sys.sqlprof_attr;
begin
 ar_profile_hints := sys.sqlprof_attr(
 'BEGIN_OUTLINE_DATA',
 'INDEX_RS_ASC(@"SEL$1" "MASTER_LOG"@"SEL$1" ("MASTER_LOG"."TASK_ID"))',
 'OUTLINE_LEAF(@"SEL$1")',
 'OPT_PARAM(''optimizer_index_caching'' 80)',
 'OPT_PARAM(''optimizer_index_cost_adj'' 1)',
 'OPT_PARAM(''_optimizer_connect_by_cost_based'' ''false'')',
 'OPT_PARAM(''_optim_peek_user_binds'' ''false'')',
 'OPT_PARAM(''_b_tree_bitmap_plans'' ''false'')',
 'DB_VERSION(''11.2.0.2'')',
 'OPTIMIZER_FEATURES_ENABLE(''11.1.0.7'')',
 'IGNORE_OPTIM_EMBEDDED_HINTS',
 'END_OUTLINE_DATA'
);
for sql_rec in (
 select t.sql_id, t.sql_text
 from dba_hist_sqltext t, dba_hist_sql_plan p
 where t.sql_id = p.sql_id and p.sql_id = 'sehy678ujy345' and p.plan_hash_value = 3709384 and p.parent_id is null
 ) loop
 DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
 sql_text => sql_rec.sql_text,profile => ar_profile_hints,name => 'PROFILE_'||sql_rec.sql_id
 );
 end loop;
end;
/

Posted in Baselines, Uncategorized | Tagged: , , , , , , , , , , , , , | Leave a Comment »

SPM and Profiles -Part2

Posted by Sumit on November 21, 2011

Converting baselines into profiles

In my last post, we have discussed various workarounds to fix the execution plan of the query if its not picking baseline.

Of the given 3 methods, I was interested in the 3rd one. What got me interested is the idea if we can create profiles from  baselines. 

The next obvious question is “why you need to do so”.

The 2 reasons are

1. Baselines not getting used. In this case you can create a profile out of baseline and then impose oracle to use this profile.

2. In 11g, we have ADG (active standby database). Guess what!!! Baselines doesn’t work in ADG. So if you fix query on primary, it won’t pick the plan in standby. So you better create a profile.  Also you may need to bounce your standby in order for profile to get used (because of another bug).

Before I talk about script to convert baselines into profiles, lets step back and think whats is that thing which is common in baselines and profiles(if at all there is) and what is that thing which makes them different.

Both baselines and profiles store data in form of hints.

Only difference is in case of baselines oracle tries to regenerate the same plan using hints and if it can’t then it will not use the baseline.

However, in case of profile, oracle will use the hints to generate the execution plan which it will use. Therefore, there is no guarantee that oracle will land on same plan again and again and hence plan flip can occur.

I will soon write about hints and how oracle stores them for a given plan.

Anyway, coming back to our point, oracle stores the execution plan in form of hints. Therefore, for each plan it captures or generates, it must store them somewhere. The idea is to get those hints and create the profile.

planprofile.sql:-

Session1>select plan_name from dba_sql_plan_baselines where rownum < 2;

PLAN_NAME
------------------------------
SYS_SQL_PLAN_086da2eaeec7bdef

1 row selected.

Session1>@planprofile
enter sql_id to be fixed:- dgh672sad89j4
baseline plan name:- SYS_SQL_PLAN_086da2eaeec7bdef
enter bad plan hash value to be tuned :- 12345678
'===================OUTPUT========================='

declare
ar_profile_hints sys.sqlprof_attr;
begin
 ar_profile_hints := sys.sqlprof_attr(
 'BEGIN_OUTLINE_DATA',
 'FULL(@"SEL$4" "MRH"@"SEL$4")',
 'NO_ACCESS(@"SEL$3" "from$_subquery$_007"@"SEL$3")',
 'FULL(@"SEL$6" "MRH"@"SEL$6")',
 'NO_ACCESS(@"SEL$5" "from$_subquery$_004"@"SEL$5")',
 'PQ_DISTRIBUTE(@"SEL$F5BB74E1" "RMS"@"SEL$2" NONE BROADCAST)',
 'USE_NL(@"SEL$F5BB74E1" "RMS"@"SEL$2")',
 'LEADING(@"SEL$F5BB74E1" "H"@"SEL$1" "RMS"@"SEL$2")',
 'INDEX_RS_ASC(@"SEL$F5BB74E1" "RMS"@"SEL$2" ("METRICS_SUMMARY95"."MVIEW_NAME" "METRICS_SUMMARY95"."OWNER"))',
 'NO_ACCESS(@"SEL$F5BB74E1" "H"@"SEL$1")',
 'PQ_DISTRIBUTE(@"MRG$1" "H"@"MRG$1" BROADCAST NONE)',
 'PQ_DISTRIBUTE(@"MRG$1" "RMS"@"MRG$1" NONE BROADCAST)',
 'USE_MERGE_CARTESIAN(@"MRG$1" "H"@"MRG$1")',
 'USE_MERGE_CARTESIAN(@"MRG$1" "RMS"@"MRG$1")',
 'LEADING(@"MRG$1" "from$_subquery$_010"@"MRG$1" "RMS"@"MRG$1" "H"@"MRG$1")',
 'NO_ACCESS(@"MRG$1" "H"@"MRG$1")',
 'FULL(@"MRG$1" "RMS"@"MRG$1")',
 'NO_ACCESS(@"MRG$1" "from$_subquery$_010"@"MRG$1")',
 'OUTLINE(@"SEL$2")',
 'OUTLINE(@"SEL$1")',
 'OUTLINE_LEAF(@"MRG$1")',
 'OUTLINE_LEAF(@"SEL$5")',
 'OUTLINE_LEAF(@"SEL$6")',
 'MERGE(@"SEL$2")',
 'OUTLINE_LEAF(@"SEL$F5BB74E1")',
 'OUTLINE_LEAF(@"SEL$3")',
 'OUTLINE_LEAF(@"SEL$4")',
 'OPT_PARAM(''optimizer_index_caching'' 80)',
 'OPT_PARAM(''optimizer_index_cost_adj'' 3)',
 'OPT_PARAM(''_optimizer_connect_by_cost_based'' ''false'')',
 'OPT_PARAM(''_optim_peek_user_binds'' ''false'')',
 'OPT_PARAM(''_b_tree_bitmap_plans'' ''false'')',
 'DB_VERSION(''11.1.0.7'')',
 'OPTIMIZER_FEATURES_ENABLE(''11.1.0.7'')',
 'IGNORE_OPTIM_EMBEDDED_HINTS',
 'END_OUTLINE_DATA'
);
for sql_rec in (
 select t.sql_id, t.sql_text
 from dba_hist_sqltext t, dba_hist_sql_plan p
 where t.sql_id = p.sql_id and p.sql_id = 'dgh672sad89j4' and p.plan_hash_value = 12345678 and p.parent_id is null
 ) loop
 DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
 sql_text => sql_rec.sql_text,profile => ar_profile_hints,name => 'PROFILE_'||sql_rec.sql_id
 );
 end loop;
end;
/

That was simple. Isn’t it??

But i was not satisfied. I wanted to take this a step further. Now i want oracle to use whatever plan I want.

In case oracle had changed plan , I want oracle to use previous plan. 

In one of my database, planflip caused cpu spikes. Buffer_gets/exec increased from thousands to millions. The idea was to force old to use previous plan .

oldprofile.sql

</pre>
Sesion1>@oldprofile
enter sql_id:- 9ddv4vbt2zrxy
enter old plan hash value:- 1236769290
enter bad plan hash value to be tuned :- 3891475932
'===================OUTPUT========================='

declare
ar_profile_hints sys.sqlprof_attr;
begin
 ar_profile_hints := sys.sqlprof_attr(
 'BEGIN_OUTLINE_DATA',
 'IGNORE_OPTIM_EMBEDDED_HINTS',
 'OPTIMIZER_FEATURES_ENABLE(''11.1.0.7'')',
 'DB_VERSION(''11.1.0.7'')',
 'OPT_PARAM(''_b_tree_bitmap_plans'' ''false'')',
 'OPT_PARAM(''_optim_peek_user_binds'' ''false'')',
 'OPT_PARAM(''_optimizer_connect_by_cost_based'' ''false'')',
 'OPT_PARAM(''optimizer_index_cost_adj'' 3)',
 'OPT_PARAM(''optimizer_index_caching'' 80)',
 'OUTLINE_LEAF(@"SEL$1")',
 'INDEX(@"SEL$1" "CCS"@"SEL$1" ("COMPLETED_CUSTOMER_SHIPMENTS"."CONDITION" "COMPLETED_CUSTOMER_SHIPMENTS"."LAST_UPDATED"))',
 'END_OUTLINE_DATA'
);
for sql_rec in (
 select t.sql_id, t.sql_text
 from dba_hist_sqltext t, dba_hist_sql_plan p
 where t.sql_id = p.sql_id and p.sql_id = '9ddv4vbt2zrxy' and p.plan_hash_value = 3891475932 and p.parent_id is null
 ) loop
 DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
 sql_text => sql_rec.sql_text,profile => ar_profile_hints,name => 'PROFILE_'||sql_rec.sql_id
 );
 end loop;
end;
/

Posted in Baselines, Scripts, Scripts, Uncategorized | Tagged: , , , , , , , , , , , , , , , , , , , , , , | 1 Comment »

SPM & Profiles-Part 1

Posted by Sumit on October 23, 2011

SPM And Profiles-Part 1

Ever encountered issue when your query does not pick baseline. In some cases, even after setting fixed=Yes, it does not pick baseline.

This may happen when you try fixing the query using hints and try to link the plan of hinted query with original query.

This post is intended to provide you the solutions for some of those issues. (And like every post a script for the dba’s.)

And most important, do we need profiles now.

Why oracle is not picking my baseline

There are several reasons(and bugs) why oracle  does not pick baselines.

In my case, I tried to manually tune the query using hints and linked the plan with the original query. However, oracle refused to pick the baseline. 

In many cases reason could be

  1. Bind Variables used in the query
  2. Aliases used  for the table

Solution 1:-

Using bind variables prevents oracle from generating multiple versions of the same query and helps in reducing hard parsing. But what if the same bind variables creates trouble for you.

If  your application is using bind variable or cursor_sharing is set to “similar”or “force”, then your query should look like this.

For the test case, I will use mytab table

Session1> select  * from mytab a where a.generated=:b1;

no rows selected

You can always check the values of bind variables using following query.


Session2>select name,value_string from v$sql_bind_capture where sql_id='&sql_id' and child_number='&child';

Enter value for sql_id: 3uj38fuby1shm
Enter value for child: 0
NAME                 VALUE_STRING
-------------------- ------------------------------
:B1                  FOR
1 row selected.

In cases, where query is using bind variables like the one given above, use following approach to tune the query and the link the baseline

var b1 varchar2(20);
exec :b1:='FOR';
Session1 >select /*+ index(a MYTAB_IDX2) */ * from mytab a where a.generated=:b1;
no rows selected

Now, we can link the plan of the tuned sql with the original sql as described in earlier post.

Solution 2:-

You may need to tune the sql’s running inside plsql packages and procedures. In those cases, bind variables name could be like “:1″ which is hard to tune using traditional approach of baselines.

e.g. select * from mytab a where a.generated=:1;

To tune those sql’s you need to create a anonymous block and create a cursor like one given below.

declare
sql_stmt varchar2(4000);
id varchar2(20);
TYPE CurTyp  IS REF CURSOR;
tmpcursor    CurTyp;
begin
   id:='&id_val';
  sql_stmt:='select /*+ index(a MYTAB_IDX2) */ * from mytab where generated=:1';
  open tmpcursor for sql_stmt using id;
end;
/
Enter value for id_val: FOR

PL/SQL procedure successfully completed.

Now, you can find the sql_id of the query and link the baseline with original sql.

Session1>select sql_id,module,sql_text from v$sql where upper(sql_text) like upper('%&text%') and ( sql_text not like lower('%v$sql%') and sql_text not like '%explain plan%') group by sql_id,module,sql_text;
Enter value for text: select /*+ index(a MYTAB_IDX2) */ * from mytab where generated=:1

SQL_ID        MODULE                    SQL_TEXT
------------- ------------------------- ------------------------------------------------------------------------------------------
5vkq50nxn4gsj SQL*Plus                  declare sql_stmt varchar2(4000); id varchar2(20); TYPE CurTyp  IS REF CURSOR; tmpcursor
                                         CurTyp; begin    id:='FOR';   sql_stmt:='select /*+ index(a MYTAB_IDX2) */ * from mytab w
                                        here generated=:1';   open tmpcursor for sql_stmt using id; end;

9z3dv649q3gvy SQL*Plus                  select /*+ index(a MYTAB_IDX2) */ * from mytab where generated=:1

2 rows selected.

You can link the plan of 9z3dv649q3gvy with original query to tune it.

Solution 3:-

The second solution of using cursor may work well if query is small or using limited number of bind variables. But for page long queries, its cumbersome to concatenate multiple bind variables.

We can use profiles to bypass second approach. (profile.sql)

Profile.sql will ask for sql_id and child number of hinted sql and the sql_id and plan hash value of the bad sql_id. You can paste the output directly to create a profile.

Session1>@profile
enter hinted sql_id:- 9z3dv649q3gvy
enter child number:- 0
enter original sql_id:- 9jutgyhjutefd
enter bad plan hash value to be tuned :- 663241269
'===================OUTPUT========================='

declare
ar_profile_hints sys.sqlprof_attr;
begin
        ar_profile_hints := sys.sqlprof_attr(
                'BEGIN_OUTLINE_DATA',
                'IGNORE_OPTIM_EMBEDDED_HINTS',
                'OPTIMIZER_FEATURES_ENABLE(''11.1.0.7'')',
                'DB_VERSION(''11.1.0.7'')',
                'OPT_PARAM(''_b_tree_bitmap_plans'' ''false'')',
                'OPT_PARAM(''_optim_peek_user_binds'' ''false'')',
                'OPT_PARAM(''_optimizer_connect_by_cost_based'' ''false'')',
                'OPT_PARAM(''optimizer_index_cost_adj'' 1)',
                'OPT_PARAM(''optimizer_index_caching'' 80)',
                'OUTLINE_LEAF(@"SEL$1")',
                'INDEX_RS_ASC(@"SEL$1" "MYTAB"@"SEL$1" ("MYTAB"."GENERATED"))',
                'END_OUTLINE_DATA'
);
for sql_rec in (
        select t.sql_id, t.sql_text
         from dba_hist_sqltext t, dba_hist_sql_plan p
        where t.sql_id = p.sql_id and p.sql_id = '9jutgyhjutefd' and p.plan_hash_value = 663241269 and p.parent_id is null
                ) loop
              DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
                sql_text    => sql_rec.sql_text,profile     => ar_profile_hints,name => 'PROFILE_'||sql_rec.sql_id
                                        );
        end loop;
end;
/

You can paste the output directly to fix the sql.


Posted in Baselines, Uncategorized | Tagged: , , , , , , , , , , , , , , , | 1 Comment »

Baselines–Part II

Posted by Sumit on August 28, 2011

Baselines Part-II

In my previous post,  I had described how to implement hints through baselines without changing code. Also, I touched upon two parameters namely

1. Optimizer_capture_sql_plan_baselines              2. Optimizer_use_sql_plan_baseline 

As I had written “optimizer_capture_sql_plan_baseline if set to true, let oracle automatically capture sql plan baselines.”

Does it mean it will not capture any plan for any sql if set to false ?

What if we want to capture baselines for only selected queries automatically.

The whole answer lies in values of “ENABLED,ACCEPTED AND FIXED” column if dba_sql_plan_baselines. How!!!!!? Lets find out…

As usual, lets create a table and insert few records

Session1>show parameter capture
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     FALSE

create table test (name varchar2(10), id number(*));

begin
for i in 1..1000
loop
insert into test values ('SUMIT',i);
end loop;
commit;
end;
/
begin
for i in 1001..10000
loop
insert into test values ('BHATIA',i);
end loop;
commit;
end;
/
begin
for i in 10001..100000
loop
insert into test values ('BASELINE',i);
end loop;
commit;
end;
/
begin
for i in 100001..1000000
loop
insert into test values ('SPM',i);
end loop;
commit;
end;
/

SELECT COUNT(*),name from test group by name order by 1;

COUNT(*) NAME
---------- ----------
1000 SUMIT
9000 BHATIA
90000 BASELINE
900000 SPM

4 rows selected.

Time to query table and load the plan into the baseline.

--Inserting hint to easily identify the query
Select /*+ id=1000 */  * FROM TEST where id=1000
NAME               ID
---------- ----------
SUMIT            1000

select sql_id,exact_matching_signature,force_matching_signature from v$sql where sql_text like '%id=1000%';
SQL_ID                EXACT_MATCHING_SIGNATURE         FORCE_MATCHING_SIGNATURE
------------- -------------------------------- --------------------------------
duk2ypk5fz9g6              7784548270786280511              4428329137525653294

SELECT * FROM TABLE(dbms_xplan.display_cursor('duk2ypk5fz9g6'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------
SQL_ID  duk2ypk5fz9g6, child number 0
-------------------------------------
select /*+ id=1000 */  * FROM TEST where id=1000
Plan hash value: 1357081020
----------------------------------
| Id  | Operation         | Name |
----------------------------------
|   0 | SELECT STATEMENT  |      |
|*  1 |  TABLE ACCESS FULL| TEST |
----------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=1000)
Note
-----
- rule based optimizer used (consider using cbo)

--Creating the baseline for the plan

var v_num number;
exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'duk2ypk5fz9g6',plan_hash_value => 1357081020 );

select sql_handle, plan_name, enabled, accepted,fixed from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX
------------------------------ ------------------------------ --- --- ---
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO

As we can see, If we load the plan manually, that will plan will be enabled and accepted but not fixed.  Its time create an index and run the query again.

create index test_id on test(id);
Index created.

select /*+ id=1000 */  * FROM TEST where id=1000
NAME               ID
---------- ----------
SUMIT            1000

Oracle is still using SYS_SQL_PLAN_7118fc3f97bbe3d0 baseline.

However, if we query dba_sql_plan_baselines, we will see that oracle has started capturing baselines for this sql. (plan name SYS_SQL_PLAN_7118fc3f642e4a26)

PLAN_TABLE_OUTPUT
-----------------------------------------------------------
SQL_ID  duk2ypk5fz9g6, child number 1
-------------------------------------
select /*+ id=1000 */  * FROM TEST where id=1000
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |   554 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST |  1643 | 32860 |   554   (2)| 00:00:07 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=1000)
Note
-----
- SQL plan baseline SYS_SQL_PLAN_7118fc3f97bbe3d0 used for this statement

select sql_handle, plan_name, enabled, accepted,fixed,signature from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX             SIGNATURE
------------------------------ ------------------------------ --- --- --- ---------------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES NO NO   7784548270786280511
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO   7784548270786280511

So even if capture baseline is set to false, oracle will still capture the new plans and baselines for that particular sql onwards. We can evolve the  new plan and can check if index is getting used or not.

/*Evolving new plan */
SET SERVEROUTPUT ON
 SET LONG 10000
 set lines 175
 DECLARE
 report clob;
 BEGIN
 report := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(
 sql_handle => '&sql_handle', time_limit => &time);
 DBMS_OUTPUT.PUT_LINE(report);
 END;
 /
 Enter value for sql_handle:SYS_SQL_6c0845687118fc3f
Enter value for time:60

-------------------------------------------------------------------------------
 Evolve SQL Plan Baseline
 Report
 -------------------------------------------------------------------------------
Inputs:
 -------
 SQL_HANDLE = SYS_SQL_6c0845687118fc3f
 PLAN_NAME  =
 TIME_LIMIT = 60
VERIFY     = YES
 COMMIT     = YES
Plan: SYS_SQL_PLAN_7118fc3f642e4a26
 -----------------------------------
 Plan was verified: Time used .05 seconds.
 Passed
 performance criterion: Compound improvement ratio >= 504.88
 Plan was changed to an accepted plan.
Baseline Plan      Test Plan     Improv. Ratio
-------------      ---------     -------------
 Execution Status:        COMPLETE       COMPLETE
 Rows Processed:                 1              1
 Elapsed Time(ms):               26             0
 CPU Time(ms):                  25              0
 Buffer Gets:                 2017              4            504.25
 Disk Reads:                     0              0
 Direct Writes:                  0              0
 Fetches:                        0              0
 Executions:                     1              1
-------------------------------------------------------------------------------
 Report
 Summary
 -------------------------------------------------------------------------------
 Number of SQL plan baselines verified: 1.
 Number of SQL plan baselines evolved: 1.

As we can read in the report, Oracle has marked the new plan as accepted. Oracle keeps a tab if the plan was loaded manually or captured automatically. This can be verified from origin column of dba_sql_plan_baselines.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES YES NO AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO MANUAL-LOAD

So far, the story was pretty much straight. Here’s a quick recap what we have done
1. Created Table and Inserted records
2. Query the table and baseline the query
3. Created Index and verified new plan is loaded but not accepted.
4. Evolve the new plan and accepted=yes.
5. New plan(Index Range Scan) started getting used.

Its time to discuss the usage of enabled,accepted and fixed parameters.

TEST1:  ENABLED=NO.

For every sql_id, oracle checks if the baselines exists or not. If yes, then it will filter all the enabled plans. The plans for which enabled=NO will not be considered even if accepted and fixed are set to yes.

Other than this, if any plan is set enabled=yes for a query,oracle will start capturing new plans also.

Therefore, enabled is the first level. If enabled is set to NO,oracle will mark not to use and evolve that plan.

Lets have a test case. I will mark enabled =no for the plan that was using index and check which plan is used.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES YES NO AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO MANUAL-LOAD

/* Setting Enabled=NO for SYS_SQL_PLAN_7118fc3f642e4a26 */
declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle => '&sql_handle',plan_name  => '&plan_name',attribute_name => 'ENABLED',   attribute_value => 'NO');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f642e4a26

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  NO YES  NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO  MANUAL-LOAD
2 rows selected.

So, plan SYS_SQL_PLAN_7118fc3f642e4a26 is accepted but not enabled. Lets execute the query again and see which plan is getting used.

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
SQL_ID  duk2ypk5fz9g6, child number 1
-------------------------------------
select /*+ id=1000 */  * FROM TEST where id=1000
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |   554 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST |  1643 | 32860 |   554   (2)| 00:00:07 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=1000)
Note
-----
- SQL plan baseline SYS_SQL_PLAN_7118fc3f97bbe3d0 used for this statement

Oracle choses SYS_SQL_PLAN_7118fc3f97bbe3, since that plan is still enabled and accepted.
Therefore, minimum requirement for oracle to use a plan as baseline is, it should be marked both as ENABLED and ACCEPTED.

The next level is Accepted. In this level oracle will pick all the plans that are accepted to the users and discard all “ACCEPTED=NO” plans. As we had already seen,there can be more than one plan for accepted=yes. All these plans are already evolved plans and are candidate for being  the final execution plan.

If no plan is marked “FIXED=YES”, then oracle will pick any of these plans based on the costing.

All those plans which are “ENABLED=YES” and “ACCEPTED=NO”, are candidates for evolution. We can also however marked then accepted=yes manually.

Next and the last level is Fixed. If any plan is fixed oracle will use that plan only. If more than one plan is fixed, oracle will use costing as criteria to select the plan among those.

TEST2:  Setting any one plan as FIXED=YES

Lets mark index plan as accepted again and FTS plan as fixed.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  NO  YES NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO  MANUAL-LOAD

/*Resetting SYS_SQL_PLAN_7118fc3f642e4a26 to Enabled */
declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle =>'&sql_handle',plan_name=>'&plan_name',attribute_name =>'ENABLED',attribute_value =>'YES');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f642e4a26

/*Setting SYS_SQL_PLAN_7118fc3f97bbe3d0 to FIXED */
declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle =>'&sql_handle',plan_name=>'&plan_name',attribute_name=>'FIXED',attribute_value=>'YES');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f97bbe3d0

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES YES NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD

Executing the query and checking the plan again

SELECT * FROM TABLE(dbms_xplan.display_cursor('duk2ypk5fz9g6'));
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
SQL_ID  duk2ypk5fz9g6, child number 1
-------------------------------------
select /*+ id=1000 */  * FROM TEST where id=1000
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |   554 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST |  1643 | 32860 |   554   (2)| 00:00:07 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=1000)
Note
-----
- SQL plan baseline SYS_SQL_PLAN_7118fc3f97bbe3d0 used for this statement

As we can confirm oracle start using FTS as that plan is marked fixed.

TEST3: Setting FIXED=YES for more than one plan

Lets mark second plan “FIXED=YES” and re-execute the query

/*Setting SYS_SQL_PLAN_7118fc3f642e4a26 to FIXED */
declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle=>'&sql_handle',plan_name=>'&plan_name',attribute_name=>'FIXED',attribute_value=>'YES');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f642e4a26

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;

SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES YES YES AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD

select /*+ id=1000 */  * FROM TEST where id=1000
NAME               ID
---------- ----------
SUMIT            1000

1 row selected.

SELECT * FROM TABLE(dbms_xplan.display_cursor('duk2ypk5fz9g6'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
SQL_ID  duk2ypk5fz9g6, child number 0
-------------------------------------
select /*+ id=1000 */  * FROM TEST where id=1000
Plan hash value: 1699862855
---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |       |       |     1 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST    |     1 |    20 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TEST_ID |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=1000)
Note
-----
- dynamic sampling used for this statement
- SQL plan baseline SYS_SQL_PLAN_7118fc3f642e4a26 used for this statement

Test 4:

Also, if any of the plan is marked as fixed, oracle will stop capturing and evolving new plans.
To simulate the test, lets again mark the plan(using index) as fixed=no and accepted=no.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;

SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES YES YES AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD

/* Resetting SYS_SQL_PLAN_7118fc3f642e4a26 to FIXED=NO */
declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle => '&sql_handle',plan_name  => '&plan_name',attribute_name => 'FIXED',   attribute_value => 'NO');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f642e4a26

/* Resetting SYS_SQL_PLAN_7118fc3f642e4a26 to ACCEPTED=NO */
declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle => '&sql_handle',plan_name  => '&plan_name',attribute_name => 'ACCEPTED',   attribute_value => 'NO');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f642e4a26

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES NO  NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD

Lets try to evolve the index plan (SYS_SQL_PLAN_7118fc3f642e4a26) again, like we did previously. The only difference is fixed=yes this time for plan using FTS

/* TRYING TO EVOLVE SYS_SQL_PLAN_7118fc3f642e4a26 */
SET SERVEROUTPUT ON
SET LONG 10000
set lines 175
DECLARE
report clob;
BEGIN
report := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(
sql_handle => '&sql_handle', time_limit => &time);
DBMS_OUTPUT.PUT_LINE(report);
END;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for time: 60
-------------------------------------------------------------------------------
Evolve SQL Plan Baseline
Report
-------------------------------------------------------------------------------
Inputs:
-------
SQL_HANDLE = SYS_SQL_6c0845687118fc3f
PLAN_NAME  =
TIME_LIMIT = 60
VERIFY     = YES
COMMIT     = YES
-------------------------------------------------------------------------------
Report
Summary
-------------------------------------------------------------------------------
There were no SQL plan baselines that required processing.

As we can confirm, plan SYS_SQL_PLAN_7118fc3f642e4a26 is not evolved since SYS_SQL_PLAN_7118fc3f97bbe3d0 was already fixed.

TEST5:

Lets go back a step further and drop the baseline as well as index. We will try to simulate a test case to check if oracle captures new plan if any plan is marked as FIXED=YES

SET SERVEROUTPUT ON
DECLARE
l_plans_dropped  PLS_INTEGER;
BEGIN
l_plans_dropped := DBMS_SPM.drop_sql_plan_baseline (
sql_handle => 'SYS_SQL_6c0845687118fc3f',
plan_name  => 'SYS_SQL_PLAN_7118fc3f642e4a26');

DBMS_OUTPUT.put_line(l_plans_dropped);
END;
/

drop index test_id;
Index dropped.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD
1 row selected.

So, we are back to square one from where we have started. Lets again create the same index and query the table to see if it still capture new plans.

create index test_id on test(id);
Index created.

select /*+ id=1000 */  * FROM TEST where id=1000;
NAME               ID
---------- ----------
SUMIT            1000
1 row selected.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;

SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD

1 row selected.

As we can see, oracle has stopped capturing new plans for this sql as SYS_SQL_PLAN_7118fc3f97bbe3d0 is already fixed.

Lets mark fixed=NO again and re-execute the query. Oracle should capturing the plan again for this query.


select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES YES MANUAL-LOAD
1 row selected.

declare
myplan pls_integer;
begin
myplan:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE (sql_handle => '&sql_handle',plan_name  => '&plan_name',attribute_name => 'FIXED',   attribute_value => 'NO');
end;
/
Enter value for sql_handle: SYS_SQL_6c0845687118fc3f
Enter value for plan_name: SYS_SQL_PLAN_7118fc3f97bbe3d0

select /*+ id=1000 */  * FROM TEST where id=1000
NAME               ID
---------- ----------
SUMIT            1000
1 row selected.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;

SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES NO  NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES YES NO  MANUAL-LOAD

2 rows selected.

So, as we can confirm oracle again started capturing new plans we turn FIXED=NO.

Here’s the quick summary,

1.  ENABLED=YES (For any of the plan) :- Oracle will start capturing new plans for those queries.

2. Enabled=NO :-  Than plan won’t we used.

3.  Accepted=Yes (Any one Plan) :- That plan will be used for execution

4.  Accepted=YES (For Multiple plans):- Any one plan can be used if fixed=no for all plans.

5. Accepted=No: Plan wont be used.

6.  FIXED=YES (for only one plan) Only that plan will be used and oracle will stop capturing/evolving new plans.

7.  FIXED=YES (for many plans) Oracle will chose execution plan only from that pool.

SPECIAL CASE :-ENABLED=YES,FIXED=YES BUT ACCEPTED=NO.

What if in our given scenario, we mark SYS_SQL_PLAN_7118fc3f97bbe3d0 as fixed and enabled but not accepted. Will oracle capture the new plan and will it evolve it.

select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES NO  YES MANUAL-LOAD
1 row selected.

Lets discuss the above scenario and try to figure out who takes precedence under what condition

select /*+ id=1000 */  * FROM TEST where id=1000;
NAME               ID
---------- ----------
SUMIT            1000
1 row selected.
select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;
SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES NO  NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES NO  YES MANUAL-LOAD
2 rows selected.

Oracle has captured new plan. Lets try to evolve that one also.

SET SERVEROUTPUT ON
SET LONG 10000
set lines 175
DECLARE
report clob;
BEGIN
report := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(
sql_handle => '&sql_handle', time_limit => &time);
DBMS_OUTPUT.PUT_LINE(report);
END;
/
-------------------------------------------------------------------------------
Evolve SQL Plan Baseline
Report
-------------------------------------------------------------------------------

Inputs:
-------
SQL_HANDLE = SYS_SQL_6c0845687118fc3f
PLAN_NAME  =
TIME_LIMIT =
60
VERIFY     = YES
COMMIT     = YES

-------------------------------------------------------------------------------
Report
Summary
-------------------------------------------------------------------------------
There were no SQL plan baselines that required processing.
select sql_handle, plan_name, enabled, accepted,fixed,origin from dba_sql_plan_baselines where signature=7784548270786280511;

SQL_HANDLE                     PLAN_NAME                      ENA ACC FIX ORIGIN
------------------------------ ------------------------------ --- --- --- --------------
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f642e4a26  YES NO  NO  AUTO-CAPTURE
SYS_SQL_6c0845687118fc3f       SYS_SQL_PLAN_7118fc3f97bbe3d0  YES NO  YES MANUAL-LOAD

2 rows selected.

ENABLED takes precedence over FIXED in case of capturing the new plan and vice versa in case of evolving.

I hope above article will help in understanding the role/usage of ENABLE/ACCEPTED/FIXED  parameters. Please do write in case you find any discrepancy or want to share some details

Posted in Baselines, Uncategorized | Tagged: , , , , , , , , , , , , , , , , , , , , , | 4 Comments »

Implementing Hints through Baseline

Posted by Sumit on June 11, 2011

Baselines

SQL Plan Management(SPM) provides a mechanism to prevent unwanted plan flips.

Whenever a query is hard parsed, oracle produces several execution plan and compares it with the accepted plan in a baseline. If a match is found, oracle picks that plan.

The behaviour of baseline is governed by 2 parameters.

  1. Optimizer_capture_sql_plan_baselines
  2. Optimizer_use_sql_plan_baseline

optimizer_capture_sql_plan_baseline if set to true, let oracle automatically capture sql plan baselines. The default value is false

Optimizer_use_sql_plan_baseline, if set to true, force oracle to use the sql plan baseline (if present). The default is true.

Implementing HINTS without changing code

Environment Setting :-

  • Optimizer_capture_sql_plan_baselines (false)
  • Optimizer_use_sql_plan_baseline (true)
I created mytab table CTAS dba_objects
Session1>desc mytab
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER VARCHAR2(30)
OBJECT_NAME VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(19)
CREATED DATE
LAST_DDL_TIME DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NUMBER
EDITION_NAME VARCHAR2(30)

Step 1> Query the mytab table without index.


select /*+woindex */ * from mytab where GENERATED='FOR';

no rows selected

SELECT * FROM TABLE(dbms_xplan.display_cursor('0ytzpgnhg1g83'));
SQL_ID  0ytzpgnhg1g83, child number 0
-------------------------------------
select /*+woindex */ * from mytab where GENERATED='FOR'
Plan hash value: 96696846
---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |       |       |   124K(100)|          |
|*  1 |  TABLE ACCESS FULL| MYTAB |  4819K|   422M|   124K  (3)| 00:24:54 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("GENERATED"='FOR')

select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines;
no rows selected

Step 2> No baseline yet exists for the current query. Lets baseline the plan to make sure it does not pick index automatically so that we can simulate the test.

var v_num number;
exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => '0ytzpgnhg1g83',plan_hash_value => 96696846 );
PL/SQL procedure successfully completed.
select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines;
SQL_TEXT                                                                         SQL_HANDLE                     PLAN_NAME                      ENA ACC

-------------------------------------------------------------------------------- ------------------------------ ------------------------------ --- ---

select /*+woindex */ * from mytab where GENERATED='FOR'                          SYS_SQL_50969e88fdd635aa       SYS_SQL_PLAN_fdd635aada00620d  YES YES

1 row selected.

Step 3> Lets create an index

create index mytab_idx2 on mytab(GENERATED) parallel 4;
Index created.

alter index mytab_idx2 noparallel;

Index altered.

Step4> Execute the query to confirm its not using the index since optimizer_use_sql_plan_baseline is set to true.


select * FROM TABLE(dbms_xplan.display_cursor('0ytzpgnhg1g83',1));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0ytzpgnhg1g83, child number 1
-------------------------------------
select /*+woindex */ * from mytab where GENERATED='FOR'
Plan hash value: 96696846
---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |       |       |   124K(100)|          |
|*  1 |  TABLE ACCESS FULL| MYTAB |  4819K|   422M|   124K  (3)| 00:24:54 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("GENERATED"='FOR')
Note
-----
   - SQL plan baseline SYS_SQL_PLAN_fdd635aada00620d used for this statement
22 rows selected.

Step5>Execute the query with index hint and create the baseline.

select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR';

no rows selected

Select * FROM TABLE(dbms_xplan.display_cursor('ay757nb7anm56'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
SQL_ID  ay757nb7anm56, child number 0
-------------------------------------
select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR'
Plan hash value: 3007699452
------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |       |       |   995 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| MYTAB      |  4819K|   422M|   995   (1)| 00:00:12 |
|*  2 |   INDEX RANGE SCAN          | MYTAB_IDX2 |  4896K|       |    90   (2)| 00:00:02 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("GENERATED"='FOR')
19 rows selected.

exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'ay757nb7anm56',plan_hash_value => '3007699452' );
select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines;
SQL_TEXT                                                                         SQL_HANDLE                     PLAN_NAME                      ENA ACC

-------------------------------------------------------------------------------- ------------------------------ ------------------------------ --- ---
select /*+woindex */ * from mytab where GENERATED='FOR'                          SYS_SQL_50969e88fdd635aa       SYS_SQL_PLAN_fdd635aa041dae64  YES NO

select /*+woindex */ * from mytab where GENERATED='FOR'                          SYS_SQL_50969e88fdd635aa       SYS_SQL_PLAN_fdd635aada00620d  YES YES

select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR'          SYS_SQL_5229297eca7bb2c7       SYS_SQL_PLAN_ca7bb2c7041dae64  YES YES

3 rows selected.

Step6> Now here, you can see that plan(SYS_SQL_PLAN_fdd635aa041dae64 ) being automatically linked with sql_handle (SYS_SQL_50969e88fdd635aa).
You can accept it.
In case, plan is not linked with sql_handle, use the below method to link plan manually.

exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'ay757nb7anm56',plan_hash_value => 3007699452 ,sql_handle => 'SYS_SQL_50969e88fdd635aa');

select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines;
SQL_TEXT                                                                         SQL_HANDLE                     PLAN_NAME                      ENA ACC
-------------------------------------------------------------------------------- ------------------------------ ------------------------------ --- ---
select /*+woindex */ * from mytab where GENERATED='FOR'                          SYS_SQL_50969e88fdd635aa       SYS_SQL_PLAN_fdd635aa041dae64  YES YES

select /*+woindex */ * from mytab where GENERATED='FOR'                          SYS_SQL_50969e88fdd635aa       SYS_SQL_PLAN_fdd635aada00620d  YES YES

select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR'          SYS_SQL_5229297eca7bb2c7       SYS_SQL_PLAN_ca7bb2c7041dae64  YES YES

3 rows selected.

dbms_spm.load_plans_from_cursor_cache(sql_id => ‘<hinted_sqlid>’,plan_hash_value=><hinted_plan_value>,sql_handle=>’<sql handle of original query>’)

Posted in Baselines, Uncategorized | Tagged: , , , , , , , , , , , , | 2 Comments »

Mytab Table

Posted by Sumit on June 10, 2011

Mytab structure :- CTAS dba_objects

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(30)
 OBJECT_NAME                                        VARCHAR2(128)
 SUBOBJECT_NAME                                     VARCHAR2(30)
 OBJECT_ID                                          NUMBER
 DATA_OBJECT_ID                                     NUMBER
 OBJECT_TYPE                                        VARCHAR2(19)
 CREATED                                            DATE
 LAST_DDL_TIME                                      DATE
 TIMESTAMP                                          VARCHAR2(19)
 STATUS                                             VARCHAR2(7)
 TEMPORARY                                          VARCHAR2(1)
 GENERATED                                          VARCHAR2(1)
 SECONDARY                                          VARCHAR2(1)
 NAMESPACE                                          NUMBER
 EDITION_NAME                                       VARCHAR2(30)
Session1>@tableinfo
enter table name :- mytab

INDEX_NAME                     COLUMN_NAME                              COLUMN_POSITION
------------------------------ ---------------------------------------- ---------------
MYTAB_IDX                      OWNER                                                  1
MYTAB_IDX                      OBJECT_NAME                                            2
MYTAB_IDX                      SUBOBJECT_NAME                                         3
MYTAB_IDX2                     GENERATED                                              1

(Size) Mb       Size(Gb)
----------     ----------
3581.5      3.49755859

Posted in Testing Env., Uncategorized | Tagged: , | 1 Comment »

xplanprofile.sql

Posted by Sumit on April 1, 2011

Xplanprofile.sql :- This script is used to generate profile by using explain plan.

/*
Name :- xplanprofile.sql
Db Version :- 11.1.0.7
Author :- Sumit Bhatia
Version :- 1.1
Purpose :- Create a profile
Input :- original sql_id and original plan_hash_value
*/
set feedback off
set echo off
set timing off
set pagesize 0
set heading off verify off
accept orig_sql_id prompt 'enter original sql_id:- '
accept plan_hash prompt'enter bad plan hash value to be tuned :- '
prompt '===================OUTPUT========================='
select chr(10) from dual;

select 'declare' from dual;
select 'ar_profile_hints sys.sqlprof_attr;' from dual;
select 'begin' from dual;
select chr(9)||'ar_profile_hints := sys.sqlprof_attr(' from dual;
select chr(9)||chr(9)||'''BEGIN_OUTLINE_DATA'',' from dual;

SELECT chr(9)||chr(9)||''''||regexp_replace(extractvalue(value(d), '/hint'),'''','''''')||''','
 from
 xmltable('/*/outline_data/hint'
 passing (
 select
 xmltype(other_xml) as xmlval
 from
 plan_table
 where
 other_xml is not null
 and
 rownum=1
 )
 )
d;

select chr(9)||chr(9)||'''END_OUTLINE_DATA'''||chr(10)||');'||chr(10)||'for sql_rec in ('||chr(10)||chr(9)||'select t.sql_id, t.sql_text'||chr(10)||chr(9)||' from dba_hist_sqltext t, dba_hist_sql_plan p' ||chr(10)||chr(9)|| 'where t.sql_id = p.sql_id and p.sql_id = ''&orig_sql_id'' and p.plan_hash_value = &plan_hash and p.parent_id is null'||chr(10)||chr(9)||chr(9)||') loop'||chr(10)||chr(9)||' DBMS_SQLTUNE.IMPORT_SQL_PROFILE('||chr(10)||chr(9)||chr(9)||'sql_text => sql_rec.sql_text,profile => ar_profile_hints,name => ''PROFILE_''||sql_rec.sql_id'||CHR(10)||chr(9)||chr(9)||chr(9)||chr(9)||chr(9)||');'||chr(10)||chr(9)||'end loop;'||chr(10)||'end;'||chr(10)||'/' FROM DUAL;
prompt '===================OUTPUT========================='
set heading on
set pages 500
undef sql_id
undef child_no

Posted in Uncategorized | 1 Comment »

Oldprofile.sql

Posted by Sumit on April 1, 2011

OldProfile.sql:- This script can be used to force oracle to use the given plan by creating profile over top of it.

/*
Name :- Oldprofile.sql
Db Version :- 11.1.0.7
Author :- Sumit Bhatia
Version :- 1.1
Purpose :- Create a profile to force the old plan
Input :- sql_id, old plan hash value, bad plan hash value
*/
set feedback off
set echo off
set timing off
set pagesize 0
set heading off verify off
accept sql_id prompt ‘enter sql_id:- ‘
accept old_plan_hash_value prompt’enter old plan hash value:- ‘
accept plan_hash prompt’enter bad plan hash value to be tuned :- ‘
prompt ‘===================OUTPUT=========================’
select chr(10) from dual;

select ‘declare’ from dual;
select ‘ar_profile_hints sys.sqlprof_attr;’ from dual;
select ‘begin’ from dual;
select chr(9)||’ar_profile_hints := sys.sqlprof_attr(‘ from dual;
select chr(9)||chr(9)||”’BEGIN_OUTLINE_DATA”,’ from dual;

SELECT chr(9)||chr(9)||””||regexp_replace(extractvalue(value(d), ‘/hint’),””,”””)||”’,’
from
xmltable(‘/*/outline_data/hint’
passing (
select
xmltype(other_xml) as xmlval
from
dba_hist_sql_plan
where
sql_id like nvl(‘&sql_id’,sql_id)
and plan_hash_value=&old_plan_hash_value
and other_xml is not null
and rownum < 2
)
)
d;

select chr(9)||chr(9)||”’END_OUTLINE_DATA”’||chr(10)||’);’||chr(10)||’for sql_rec in (‘||chr(10)||chr(9)||’select t.sql_id, t.sql_text’||chr(10)||chr(9)||’ from dba_hist_sqltext t, dba_hist_sql_plan p’ ||chr(10)||chr(9)|| ‘where t.sql_id = p.sql_id and p.sql_id = ”&sql_id” and p.plan_hash_value = &plan_hash and p.parent_id is null’||chr(10)||chr(9)||chr(9)||’) loop’||chr(10)||chr(9)||’ DBMS_SQLTUNE.IMPORT_SQL_PROFILE(‘||chr(10)||chr(9)||chr(9)||’sql_text => sql_rec.sql_text,profile => ar_profile_hints,name => ”PROFILE_”||sql_rec.sql_id’||CHR(10)||chr(9)||chr(9)||chr(9)||chr(9)||chr(9)||’);’||chr(10)||chr(9)||’end loop;’||chr(10)||’end;’||chr(10)||’/’ FROM DUAL;
prompt ‘===================OUTPUT=========================’
set heading on
set pages 500
undef sql_id
undef old_plan_hash_value
undef plan_hash


Posted in Baselines, Scripts, Scripts, Uncategorized | Tagged: , , , , , , , | 1 Comment »

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: