In an earlier blog post I showed how I used coe_xfr_sql_profile.sql from the sqlt toolkit from Oracle support to force a particular sql statement to run with a more efficient plan that it had used in the past.
Today, I’m trying a slight variation. Take the problem query, run it with hints, and use coe_xfr_sql_profile.sql to apply the resulting plan to the original query. I built a quick and dirty test to make sure it works.
-- create test table with index and stats
SQL> create table test as select * from dba_tables;
SQL> create index testi on test(owner);
SQL> execute dbms_stats.gather_table_stats(NULL,'TEST');
-- run query unhinted
SQL> select sum(blocks) from test where owner='SYS';
SUM(BLOCKS)
-----------
1042402
-- show plan - uses the index
SQL> select * from
table(dbms_xplan.display_cursor(null,null,'ALL'));
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a0nw2xjnmjcxd, child number 0
-------------------------------------
select sum(blocks) from test where owner='SYS'
Plan hash value: 1551939256
--------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |
| 1 | SORT AGGREGATE | | 1 | 9 |
| 2 | TABLE ACCESS BY INDEX ROWID| TEST | 2122 | 19098 |
|* 3 | INDEX RANGE SCAN | TESTI | 2122 | |
--------------------------------------------------------------
-- use hint to force full scan
SQL> select /*+full(test) */ sum(blocks) from test
where owner='SYS';
SUM(BLOCKS)
-----------
1042402
-- get plan with full scan
SQL> select * from
table(dbms_xplan.display_cursor(null,null,'ALL'));
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 5521zhmq67vun, child number 0
-------------------------------------
select /*+full(test) */ sum(blocks) from test
where owner='SYS'
Plan hash value: 3467505462
----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 295 (100)|
| 1 | SORT AGGREGATE | | 1 | 9 | |
|* 2 | TABLE ACCESS FULL| TEST | 2122 | 19098 | 295 (1)|
----------------------------------------------------------------
So, let’s pretend that sql_id=a0nw2xjnmjcxd is the real production query you are trying to tune. Without hints it is doing an index range scan. With a hint you run a similar query forcing a full scan. The new query, sql_id=5521zhmq67vun has a plan with this hash value: 3467505462. So, I used coe_xfr_sql_profile.sql to force the unhinted original query to run with the hinted query’s plan:
cd /var/opt/oracle/admin/sqlt/utl
-- login to sqlplus as system
@coe_xfr_sql_profile.sql a0nw2xjnmjcxd 3467505462
-- login to sqlplus as system
@coe_xfr_sql_profile_a0nw2xjnmjcxd_3467505462.sql
Now when I run the original query it runs with the new plan and indicates that the profile is in use:
SQL> select sum(blocks) from test where owner='SYS';
SUM(BLOCKS)
-----------
1042402
SQL> select * from
table(dbms_xplan.display_cursor(null,null,'ALL'));
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a0nw2xjnmjcxd, child number 0
-------------------------------------
select sum(blocks) from test where owner='SYS'
Plan hash value: 3467505462
----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 295 (100)|
| 1 | SORT AGGREGATE | | 1 | 9 | |
|* 2 | TABLE ACCESS FULL| TEST | 2122 | 19098 | 295 (1)|
----------------------------------------------------------------
Note
-----
- SQL profile coe_a0nw2xjnmjcxd_3467505462 used for
this statement
I edited the output to make it more readable. See the zip with the full scripts and logs.
So, if you have a recurring production SQL query that runs faster with hints just run that query once with the hints and then use coe_xfr_sql_profile.sql to force the real query to run unchanged but with the same plan as the hinted query.
– Bobby