Monday, 1 March 2021

 SQL profiles:


A SQL profile contains supplementary or additional statistics specific to a SQL query. SQL profile information is stored in the data dictionary. The optimizer uses this information during optimization to determine the most optimal plan.

Below steps will help to implement SQL profile for a query in different scenarios:

1. SQL Tuning Advisor task created for a slow performing query and the task includes a recommendation to create SQL profile.

2. Restore old execution plan for a query.

3. Copy execution plan for a query from one database to another database.


Prerequisite Steps

• Identify the SQL_ID and plan hash value for the slow performing query.

• Run below queries to find if there is change in plan or if a better performing plan was used.


set pages 200 linesize 200

select distinct *from (select sql_id, plan_hash_value, trunc(begin_interval_time) as begin_date

from dba_hist_snapshot natural join dba_hist_sqlstat

where begin_interval_time between

to_date('01-JAN-2021 1228','dd-mon-yyyy hh24mi')

and to_date('30-JAN-2021 1248','dd-mon-yyyy hh24mi')

and sql_id in ( ' <SQL_ID>' ) ) order by 3 desc;


Average Elapsed Time in sec for each plan: 

WITH p AS (

SELECT plan_hash_value FROM gv$sql_plan

WHERE sql_id = TRIM(‘<YOUR_SQL_ID>')

AND other_xml IS NOT NULL

UNION

SELECT plan_hash_value FROM dba_hist_sql_plan

WHERE sql_id = TRIM('&&sql_id.')

AND other_xml IS NOT NULL ),

m AS (SELECT plan_hash_value,

SUM(elapsed_time)/SUM(executions) avg_et_secs

FROM gv$sql

WHERE sql_id = TRIM('&&sql_id.')

AND executions > 0

GROUP BY

plan_hash_value ),

a AS (

SELECT plan_hash_value,

SUM(elapsed_time_total)/SUM(executions_total) avg_et_secs

FROM dba_hist_sqlstat

WHERE sql_id = TRIM('<YOUR_SQL_ID>')

AND executions_total > 0

GROUP BY

plan_hash_value )

SELECT p.plan_hash_value,

ROUND(NVL(m.avg_et_secs, a.avg_et_secs)/1e6, 3) avg_et_secs

FROM p, m, a

WHERE p.plan_hash_value = m.plan_hash_value(+)

AND p.plan_hash_value = a.plan_hash_value(+)

ORDER BY

avg_et_secs NULLS LAST;

PLAN_HASH_VALUE AVG_ET_SECS

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

12233642251     .006

3453222222       .036

1234543016      .922


From above two queries it is evident that the old plan hash value (1234543016 ) performed better.

  • Execution Steps

This section describe the process to create SQL profile for different scenarios discussed above.

• SQL Tuning Advisor:

o After identifying the candidate query’s SQL_ID and Plan Hash Value, login to the database using Enterprise Manager Cloud Control.

o Navigate to the query by searching the SQL_ID and execute the SQL Tuning Advisor for the query.

o If a SQL profile is recommended, accept the profile and test the query performance, with and without profile. 

• Restore old execution plan/Copy SQL profile to another database:

o Run the coe_xfr_sql_profile.sql in SQLT's utl subdirectory, by inputing the SQL_ID and Plan Hash Value (good) as parameters


download sqlt and unzip the file to your custom location

cd SQLT_LOCATION/sqlt/utl

login to oracle database server:

setup database env

sqlplus "/ as sysdba"

SQL> @coe_xfr_sql_profile.sql <your sql_id>  <plan_hash_value>


example:

SQL> @coe_xfr_sql_profile.sql 2fxxxxxxxxu 3731234451

Parameter 1:

SQL_ID (required)

PLAN_HASH_VALUE AVG_ET_SECS

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

3731234451 .006

3432922222 .036

2253653324 .916

17434378898

Parameter 2:

PLAN_HASH_VALUE (required)

Values passed:

~~~~~~~~~~~~~

SQL_ID : "2fxxxxxxxxu"

PLAN_HASH_VALUE: "3731234451"

Execute coe_xfr_sql_profile_2fxxxxxxxxu_3731234451.sql

on TARGET system in order to create a custom SQL Profile

with plan 3733642251 linked to adjusted sql_text.

COE_XFR_SQL_PROFILE completed.

Edit the above profile creation script and in the end change the FORCE_MATCH from FALSE to TRUE.


Create the SQL PROFILE.

SQL> @coe_xfr_sql_profile_2fxxxxxxxxu_3731234451.sql

....................

... manual custom SQL Profile has been created

COE_XFR_SQL_PROFILE_coe_2fxxxxxxxxu_3731234451 completed

SQL> 6. Post Execution Steps

• Verify the SQL profile

SQL> select name, trunc(created) ,status , FORCE_MATCHING from dba_sql_profiles where name like '%22fxxxxxxxxu%' order by created desc;

NAME TRUNC(CRE STATUS FOR

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

coe_2fxxxxxxxxu_3731234451 25-JAN-21 ENABLED YES

• Verify the Plan Hash Value using the query from prerequisites steps


 Backout Plan

• Drop the SQL profile

As sysdba

BEGIN

DBMS_SQLTUNE.DROP_SQL_PROFILE(name => '&name_of_sql_profile');

END;

/