Wednesday, November 24, 2021

Automatic SQL Tuning Adviser

Automatic SQL Tuning Adviser:

=============================
Optimizer --- Will generate and pick execution plan
Suppose Stale Table or Wrong statistics of a table 

1. Statistical Analysis 
2. Accessing Path (Using Index or not)


High Level steps for SQL Tuning Adviser:

How to find the SQL ID:

=======================
select sql_id from v$sql where sql_text like 'select * from student';

Create Tuning Task:

===================
DECLARE
l_sql_tune_task_id VARCHAR2(100);
BEGIN
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task (
sql_id => 'cdq26qbcmz1hc',
scope => DBMS_SQLTUNE.scope_comprehensive,
time_limit => 500,
task_name => 'my_tuning_task_3',
description => 'Tuning task1 for statement cdq26qbcmz1hc');
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
END;
/

Execute Tuning Task:

====================
EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => 'my_tuning_task_3');

Status of Tuning Task:
=====================
SELECT TASK_NAME, STATUS FROM DBA_ADVISOR_LOG WHERE TASK_NAME='my_tuning_task_3';

Display the Recommendation:

==========================
set long 65536
set longchunksize 65536
set linesize 100
select dbms_sqltune.report_tuning_task('my_tuning_task_3') from dual;

Drop the Tuning Task:

======================
execute dbms_sqltune.drop_tuning_task('my_tuning_task_1');

Find out state Tables:

======================
set lines 160 pages 2000
col owner format a15
col table_name format a35
col last_analyzed format a35
col num_rows for 999999999999
SELECT RPAD(owner,15,' ') Owner, RPAD(table_name,35,' ') Table_Name, num_rows, RPAD(TO_CHAR(last_analyzed,'DD-MON-YYYY HH24:MI:SS'),35,' ') last_analyzed
FROM dba_tab_statistics
WHERE owner IN ('MALLIK')
AND stale_stats='YES'
ORDER BY owner;

Gather table state:

===================
execute dbms_stats.gather_table_stats(ownname =>'MALLIK',tabname =>'STUDENT',estimate_percent =>100);


Execution logs from SQL Tuning Adviser:

=======================================

1. Run SQL statement and capture the SQL ID:


[oracle@oraclelab3 ~]$ ps -ef|grep smon
oracle    4941     1  0 Nov12 ?        00:00:16 ora_smon_TESTDB
oracle    8631  5466  0 00:55 pts/1    00:00:00 grep --color=auto smon
[oracle@oraclelab3 ~]$ sqlplus mallik/mallik

SQL*Plus: Release 19.0.0.0.0 - Production on Wed Nov 24 00:55:21 2021
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

Last Successful login time: Wed Nov 24 2021 00:16:14 +05:30

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> select * from student;

      STNO STNAME
---------- ---------------
         1 Mallik
         2 John
        10 AAA
        10 AAA
        10 AAA
        10 AAA
        10 AAA
        10 AAA
        10 AAA

9 rows selected.

2. Validate the table and make sure there table is not in stale state:


SQL> set lines 160 pages 2000
col owner format a15
col table_name format a35
col last_analyzed format a35
col num_rows for 999999999999
SELECT RPAD(owner,15,' ') Owner, RPAD(table_name,35,' ') Table_Name, num_rows, RPAD(TO_CHAR(last_analyzed,'DD-MON-YYYY HH24:MI:SS'),35,' ') last_analyzed
FROM dba_tab_statistics
WHERE owner IN ('MALLIK')
AND stale_stats='YES'
ORDER BY owner;SQL> SQL> SQL> SQL> SQL>   2    3    4    5

no rows selected

SQL> select sql_id from v$sql where sql_text like 'select * from student';

SQL_ID
-------------
cdq26qbcmz1hc

SQL>

3. Create Tuning Task for the SQL ID:


[oracle@oraclelab3 ~]$ ps -ef|grep smon
oracle    4941     1  0 Nov12 ?        00:00:16 ora_smon_TESTDB
oracle    8049  5048  0 00:48 pts/0    00:00:00 grep --color=auto smon
[oracle@oraclelab3 ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Wed Nov 24 00:58:04 2021
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> DECLARE
  2  l_sql_tune_task_id VARCHAR2(100);
BEGIN
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task (
sql_id => 'cdq26qbcmz1hc',
scope => DBMS_SQLTUNE.scope_comprehensive,
time_limit => 500,
task_name => 'my_tuning_task_1',
  3    4    5    6    7    8    9  description => 'Tuning task1 for statement cdq26qbcmz1hc');
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
END;
/ 10   11   12

PL/SQL procedure successfully completed.

SQL> 

4. Run the Tuning Task and check the status:


SQL> EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => 'my_tuning_task_1');

PL/SQL procedure successfully completed.

SQL>
SQL> SELECT TASK_NAME, STATUS FROM DBA_ADVISOR_LOG WHERE TASK_NAME='my_tuning_task_1';

TASK_NAME
--------------------------------------------------------------------------------
STATUS
-----------
my_tuning_task_1
COMPLETED

SQL> 

5. Review the recommendation provided by Tuning Task:


SQL> set long 65536
set longchunksize 65536
set linesize 100
select dbms_sqltune.report_tuning_task('my_tuning_task_1') from dual;
SQL> SQL> SQL>
DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_1')
----------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : my_tuning_task_1
Tuning Task Owner  : SYS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 500
Completion Status  : COMPLETED
Started at         : 11/24/2021 00:58:28
Completed at       : 11/24/2021 00:58:28


DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_1')
----------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Schema Name: MALLIK
SQL ID     : cdq26qbcmz1hc
SQL Text   : select * from student

-------------------------------------------------------------------------------
There are no recommendations to improve the statement.

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

SQL>

6. Delete Some rows from table and table will become in stale state:


SQL> select * from student;

      STNO STNAME
---------- ---------------
         1 Mallik
         2 John
        10 AAA
        10 AAA
        10 AAA
        10 AAA
        10 AAA
        10 AAA
        10 AAA

9 rows selected.

SQL>

SQL> delete from student where STNO=10;

7 rows deleted.

SQL> commit;

Commit complete.

SQL> select * from student;

      STNO STNAME
---------- ---------------
         1 Mallik
         2 John

SQL> set lines 160 pages 2000
col owner format a15
SQL> SQL> col table_name format a35
col last_analyzed format a35
col num_rows for 999999999999
SELECT RPAD(owner,15,' ') Owner, RPAD(table_name,35,' ') Table_Name, num_rows, RPAD(TO_CHAR(last_analyzed,'DD-MON-YYYY HH24:MI:SS'),35,' ') last_analyzed
FROM dba_tab_statistics
WHERE owner IN ('MALLIK')
AND stale_stats='YES'
ORDER BY owner;SQL> SQL> SQL>   2    3    4    5

OWNER           TABLE_NAME                               NUM_ROWS LAST_ANALYZED
--------------- ----------------------------------- ------------- -----------------------------------
MALLIK          STUDENT                                         9 24-NOV-2021 00:28:55

SQL>

7. Now you can generate the new Tuning Task and see the recommendation from it:


SQL> DECLARE
l_sql_tune_task_id VARCHAR2(100);
BEGIN
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task (
sql_id => 'cdq26qbcmz1hc',
scope => DBMS_SQLTUNE.scope_comprehensive,
time_limit => 500,
task_name => 'my_tuning_task_2',
description => 'Tuning task1 for statement cdq26qbcmz1hc');
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
END;
/  2    3    4    5    6    7    8    9   10   11   12

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => 'my_tuning_task_2');

PL/SQL procedure successfully completed.

SQL> SELECT TASK_NAME, STATUS FROM DBA_ADVISOR_LOG WHERE TASK_NAME='my_tuning_task_2';

TASK_NAME
----------------------------------------------------------------------------------------------------
STATUS
-----------
my_tuning_task_2
COMPLETED


SQL> set long 65536
set longchunksize 65536
set linesize 100
select dbms_sqltune.report_tuning_task('my_tuning_task_2') from dual;SQL> SQL> SQL>

DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_2')
----------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : my_tuning_task_2
Tuning Task Owner  : SYS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 500
Completion Status  : COMPLETED
Started at         : 11/24/2021 01:02:18
Completed at       : 11/24/2021 01:02:18


DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_2')
----------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Schema Name: MALLIK
SQL ID     : cdq26qbcmz1hc
SQL Text   : select * from student

-------------------------------------------------------------------------------
FINDINGS SECTION (1 finding)
-------------------------------------------------------------------------------

1- Statistics Finding
---------------------

DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_2')
----------------------------------------------------------------------------------------------------
  Optimizer statistics for table "MALLIK"."STUDENT" are stale.

  Recommendation
  --------------
  - Consider collecting optimizer statistics for this table.
    execute dbms_stats.gather_table_stats(ownname => 'MALLIK', tabname =>
            'STUDENT', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
            method_opt => 'FOR ALL COLUMNS SIZE AUTO');

  Rationale
  ---------

DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_2')
----------------------------------------------------------------------------------------------------
    The optimizer requires up-to-date statistics for the table in order to
    select a good execution plan.

-------------------------------------------------------------------------------
EXPLAIN PLANS SECTION
-------------------------------------------------------------------------------

1- Original
-----------
Plan hash value: 2356778634


DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_2')
----------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------
| Id  | Operation         | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |     9 |    63 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| STUDENT |     9 |    63 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

SQL>

8. In this above Tuning task has given recommendation that table is in state stat and gather stats on the table


SQL> execute dbms_stats.gather_table_stats(ownname => 'MALLIK', tabname =>'STUDENT', estimate_percent =>DBMS_STATS.AUTO_SAMPLE_SIZE,method_opt => 'FOR ALL COLUMNS SIZE AUTO');

PL/SQL procedure successfully completed.

SQL>

9. Now the table is not in stale state then you can generate the new tuning task which will not give any recommendation since table is upto date.


SQL> DECLARE
  2  l_sql_tune_task_id VARCHAR2(100);
BEGIN
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task (
  3    4    5  sql_id => 'cdq26qbcmz1hc',
scope => DBMS_SQLTUNE.scope_comprehensive,
time_limit => 500,
task_name => 'my_tuning_task_3',
description => 'Tuning task1 for statement cdq26qbcmz1hc');
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
  6  END;
/  7    8    9   10   11   12

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => 'my_tuning_task_3');

PL/SQL procedure successfully completed.

SQL> SELECT TASK_NAME, STATUS FROM DBA_ADVISOR_LOG WHERE TASK_NAME='my_tuning_task_3';

TASK_NAME
----------------------------------------------------------------------------------------------------
STATUS
-----------
my_tuning_task_3
COMPLETED


SQL> set long 65536
set longchunksize 65536
set linesize 100
select dbms_sqltune.report_tuning_task('my_tuning_task_3') from dual;
SQL> SQL> SQL>
DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_3')
----------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : my_tuning_task_3
Tuning Task Owner  : SYS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 500
Completion Status  : COMPLETED
Started at         : 11/24/2021 01:06:05
Completed at       : 11/24/2021 01:06:05


DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TUNING_TASK_3')
----------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Schema Name: MALLIK
SQL ID     : cdq26qbcmz1hc
SQL Text   : select * from student

-------------------------------------------------------------------------------
There are no recommendations to improve the statement.

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

SQL>

10. Drop those tuning tasks:


SQL> execute dbms_sqltune.drop_tuning_task('my_tuning_task_1');

PL/SQL procedure successfully completed.

SQL> execute dbms_sqltune.drop_tuning_task('my_tuning_task_2');

PL/SQL procedure successfully completed.

SQL> execute dbms_sqltune.drop_tuning_task('my_tuning_task_3');

PL/SQL procedure successfully completed.

SQL>

Regards,
Mallik

3 comments:

  1. Very clear and concise. Thank you for posting!

    ReplyDelete
  2. Hi Malik, For few sql iam getting like this -"Type of SQL statement not supported."

    ReplyDelete
    Replies
    1. Is it applicable only to select statements?

      Delete

Automation Script | Archivelog Generation Hourly Monitoring

1. List out all the running databases and pic one database where we want to monitore the archive log generation from last 1 month. [oracle@o...