SQL Profile: uma poderosa aliada no processo de Tuning

sql_profile

Quantas vezes você encontrou uma consulta usando um índice X quando você queria que ela usasse o índice Y, ou uma consulta realizando “Nested loop” para fazer um “join” entre duas tabelas quando um “Hash Join” realizaria esse trabalho muito mais rápido. Ou uma instância em que a aplicação de repente começa a utilizar um plano de execução ineficiente após o banco de dados reiniciar. Utilizando SQL Profile podemos resolver esses problemas sem alterar uma linha de código da aplicação.

O que é uma SQL Profile

SQL Profile são metadados armazenados no banco de dados que são compostos do código da instrução SQL e um conjunto de sugestões que serão utilizados pelo Otimizador para montar o plano de execução. Ao contrário da “Stored Outlines”, os “Hints” armazenados na SQL Profile não tentam ditar as operações que o Otimizador deverá utilizar no plano de execução. Em vez disso, fornecer fatores de correção aritmética que serão utilizados pelo otimizador para melhorar a estimativa de cardinalidade.

Apesar da SQL Profile gerada pelo SQL Tuning Advisor não possuir Hints semelhantes aos utilizados pelas “Stored Outlines”, podemos criar manualmente uma SQL Profile que utiliza Hints como as “Stored Outlines” para ditar ao Otimizador como deve ser o plano de execução.

Como são criadas as SQL Profile

Uma SQL Profile pode ser criada através do “SQL Tuning Advisor” (STA), esse tipo SQL Profile como foi dito anteriormente não fixa um plano de execução apenas fornece fatores de correção aritmética para melhorar as estimativas de cardinalidade, dando ao Otimizador informações mais qualificadas para escolha do plano de execução.

Outra opção para criação de SQL Profile é utilizar o script coe_xfr_sql_profile.sql, elaborado por Carlos Sierra (Oracle Support forces), esse script gera outro script para criação SQL Profile a partir das “Outlines” de um SQL_ID armazenadas na “Library Cache”. A SQL Profile gerada por este script é diferente da gerada pelo “SQL Tuning Advisor”, os “Hints” dessa profile dizem ao Otimizador que tipo de operações utilizar na elaboração do plano, tornando o plano de execução fixo.

Exemplo prático de criação SQL Profile

A seguir vamos demonstrar a criação de uma SQL Profile utilizado “SQL Tuning Advisor” e outra com o script coe_xfr_sql_profile.sql, em cada um dos exemplos vamos listar no final os “Hints” de cada uma das SQL Profile que serão utilizados para influenciar o Otimizador na elaboração do plano de execução.

Criação SQL Profile com STA

Primeiro vamos criar uma tabela que será utilizada na consulta do nosso exemplo.
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
SQL > SELECT * FROM V$VERSION where rownum < 2;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - Production

SQL >
SQL > create table tab01
  2  (pk_col number primary key,
  3  col1 number,
  4  col2 varchar2 (30),
  5  col3 date,
  6  col4 varchar2(1))
  7  /

Tabela criada.

SQL > create sequence tab01_seq
  2  /

Sequência criada.

SQL > begin
  2  for i in 1..100000 loop
  3  insert into tab01 (pk_col, col1, col2, col3, col4)
  4  select tab01_seq.nextval, tab01_seq.currval, 'asddsadasd',
  5  sysdateÍ(tab01_seq.currval/3600), 'Y' from dual;
  6  end loop;
  7  end;
  8  /

Procedimento PL/SQL concluído com sucesso.

SQL > select count(*) from tab01;

  COUNT(*)
----------
    100000

1 linha selecionada.

SQL > update tab01 set col1 = 1 where rownum < 100000;

99999 linhas atualizadas.

SQL > update tab01 set col4 = 'N' where rownum < 100;

99 linhas atualizadas.

SQL > commit;

Commit concluído.

SQL > create index tab01_col1 on tab01(col1);

Índice criado.

SQL > exec dbms_stats.gather_table_stats(ownname => USER, tabname => 'TAB01',method_opt=>'for all columns size auto',cascade=>true);

Procedimento PL/SQL concluído com sucesso.

SQL >

 
Agora vamos executar uma consulta e verificar o plano de execução gerado pelo Otimizador.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
SQL > ALTER SESSION SET statistics_level=ALL;

Sessão alterada.

SQL > select col1, col2, col3 from tab01 where col1 = 77150;

      COL1 COL2                           COL3
---------- ------------------------------ --------
     77150 asddsadasd                     06/03/16

1 linha selecionada.

SQL > @find_sql
'========================================================================'
'= INFORME UM DOS PARAMETROS ABAIXO:  SQL_TEXT OU  SQL_ID               ='
'========================================================================'
SQL_TEXT..: from tab01 where col1
SQL_ID....:

SQL_ID         CHILD  PLAN_HASH      EXECS         ETIME     AVG_ETIME USERNAME      SQL_TEXT
------------- ------ ---------- ---------- ------------- ------------- ------------- -----------------------------------------
arrf7tftg4pxg      0 2044041692          3           .03           .01 VALTER        select col1, col2, col3 from tab01 where
                                                                                     col1 = 77150


SQL > @dplan
'========================================================================'
'= INFORME UM DOS PARAMETROS ABAIXO:  SQL_ID E/OU  CHILD_NO             ='
'========================================================================'
SQL_ID...: arrf7tftg4pxg
CHILD_NO.: 0

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------
SQL_ID  arrf7tftg4pxg, child number 0
-------------------------------------
select col1, col2, col3 from tab01 where col1 = 77150

Plan hash value: 2044041692

---------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name  | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |      1 |        |       |   137 (100)|          |      1 |00:00:00.01 |     499 |
|*  1 |  TABLE ACCESS FULL| TAB01 |      1 |  50000 |  1123K|   137   (1)| 00:00:02 |      1 |00:00:00.01 |     499 |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("COL1"=77150)


SQL >

 

Podemos observar que o plano de execução gerado pelo Otimizador faz um “table full scan” na tabela TAB01, e acessa 499 Buffers para retornar 1 linha. Na sequência vamos utilizar “SQL Tuning Advisor” para verificar se o Otimizador consegue gerar uma plano de execução de melhor qualidade.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
SQL > @create_tuning_task.sql;
Task_Name: tuning_arrf7tftg4pxg
Informe o valor para sql_id: arrf7tftg4pxg
Informe o valor para time_limit: 3000

Procedimento PL/SQL concluído com sucesso.

RECOMMENDATIONS
------------------------------------------------------------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : tuning_arrf7tftg4pxg
Tuning Task Owner  : VALTER
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 3000
Completion Status  : COMPLETED
Started at         : 03/27/2016 11:53:33
Completed at       : 03/27/2016 11:53:36

-------------------------------------------------------------------------------
Schema Name: VALTER
SQL ID     : arrf7tftg4pxg
SQL Text   : select col1, col2, col3 from tab01 where col1 = 77150

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

1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
  Foi encontrado um plano de execução potencialmente melhor para esta
  instrução.

  Recommendation (estimated benefit: 99.39%)
  ------------------------------------------
  - Considere a aceitação do perfil SQL recomendado.
    execute dbms_sqltune.accept_sql_profile(task_name =>
            'tuning_arrf7tftg4pxg', task_owner => 'VALTER', replace => TRUE);

  Validation results
  ------------------
  O SQL profile foi testado executando-se tanto o seu plano quanto o plano
  original e medindo suas respectivas estatísticas de execução. Um plano pode
  ter sido somente parcialmente executado se o outro puder ser executado até a
  conclusão em menos tempo.

                           Original Plan  With SQL Profile  % Improved
                           -------------  ----------------  ----------
  Completion Status:            COMPLETE          COMPLETE
  Elapsed Time (s):             .002539           .000041      98.38 %
  CPU Time (s):                 .002599                 0        100 %
  User I/O Time (s):                  0                 0
  Buffer Gets:                      499                 3      99.39 %
  Physical Read Requests:             0                 0
  Physical Write Requests:            0                 0
  Physical Read Bytes:                0                 0
  Physical Write Bytes:               0                 0
  Rows Processed:                     1                 1
  Fetches:                            1                 1
  Executions:                         1                 1

  Notes
  -----
  1. As estatísticas para the original plan foram calculadas com média com
  base em 10 execuções.
  2. As estatísticas para the SQL profile plan foram calculadas com média com
  base em 10 execuções.

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

1- Original With Adjusted Cost
------------------------------
Plan hash value: 2044041692

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |     1 |    23 |   137   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TAB01 |     1 |    23 |   137   (1)| 00:00:02 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("COL1"=77150)

2- Using SQL Profile
--------------------
Plan hash value: 330808811

------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |     1 |    23 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB01      |     1 |    23 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TAB01_COL1 |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("COL1"=77150)

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


SQL >

 

No relatório acima podemos verificar que o STA recomenda a criação de uma SQL Profile que vai proporcionar uma melhoria de 99.39% no plano de execução, se observarmos o plano de execução sugerido vamos constatar a utilização do índice TAB01_COL1 para acessar as linhas solicitadas pela consulta.
Para validar a sugestão do STA vamos criar a SQL Profile sugerida e executar a consulta novamente.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
SQL > execute dbms_sqltune.accept_sql_profile(task_name => 'tuning_arrf7tftg4pxg', task_owner => 'VALTER', replace => TRUE);

Procedimento PL/SQL concluído com sucesso.

SQL > alter system flush shared_pool;

Sistema alterado.

SQL > select col1, col2, col3 from tab01 where col1 = 77150;

      COL1 COL2                           COL3
---------- ------------------------------ --------
     77150 asddsadasd                     06/03/16

SQL > @dplan
'========================================================================'
'= INFORME UM DOS PARAMETROS ABAIXO:  SQL_ID E/OU  CHILD_NO             ='
'========================================================================'
SQL_ID...: arrf7tftg4pxg
CHILD_NO.:

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------
SQL_ID  arrf7tftg4pxg, child number 0
-------------------------------------
select col1, col2, col3 from tab01 where col1 = 77150

Plan hash value: 330808811

-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |        |       |     2 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB01      |      1 |    23 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TAB01_COL1 |      1 |       |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("COL1"=77150)

Note
-----
   - SQL profile SYS_SQLPROF_0153b8917ef00000 used for this statement
   - Warning: basic plan statistics not available. These are only collected when:
       * hint 'gather_plan_statistics' is used for the statement or
       * parameter 'statistics_level' is set to 'ALL', at session or system level


SQL >

 

Ao examinar o plano de execução da consulta verificamos que o plano sugerido (que usa o índice TAB01_COL1) foi utilizado e na seção “Note” encontramos a confirmação da utilização da SQL Profile “SQL profile SYS_SQLPROF_0153b8917ef00000 used for this statement”.
Agora vamos verificar quais foram os “Hints” utilizados por essa SQL Profile para influenciar o Otimizador na criação do plano de execução.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
SQL > conn sys@lab11 as sysdba;
Informe a senha:
Conectado.
SQL > @sql_profile_hints11;
Informe o valor para name: SYS_SQLPROF_0153b8917ef00000

HINT
------------------------------------------------------------------------------------------------------------------------------------------------------
OPT_ESTIMATE(@"SEL$1", TABLE, "TAB01"@"SEL$1", SCALE_ROWS=2e-05)
OPT_ESTIMATE(@"SEL$1", INDEX_SCAN, "TAB01"@"SEL$1", "TAB01_COL1", SCALE_ROWS=2e-05)
OPTIMIZER_FEATURES_ENABLE(default)

SQL >

 

Criação SQL Profile com script coe_xfr_sql_profile

Vamos criar uma SQL Profile do plano otimizado pelo STA, utilizando o script coe_xfr_sql_profile.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
SQL> select col1, col2, col3 from tab01 where col1 = 77150;

      COL1 COL2                           COL3
---------- ------------------------------ --------
     77150 asddsadasd                     06/03/16

SQL> @coe_xfr_sql_profile.sql;

Parameter 1:
SQL_ID (required)

Informe o valor para 1: arrf7tftg4pxg


PLAN_HASH_VALUE AVG_ET_SECS
--------------- -----------
      330808811        ,011

Parameter 2:
PLAN_HASH_VALUE (required)

Informe o valor para 2: 330808811

Values passed:
~~~~~~~~~~~~~
SQL_ID         : "arrf7tftg4pxg"
PLAN_HASH_VALUE: "330808811"


Execute coe_xfr_sql_profile_arrf7tftg4pxg_330808811.sql
on TARGET system in order to create a custom SQL Profile
with plan 330808811 linked to adjusted sql_text.


COE_XFR_SQL_PROFILE completed.
SQL>

 

A execução do script coe_xfr_sql_profile produz um outro script no diretório “c:\temp” preparado para gerar uma SQL Profile, vamos executar esse script e verificar quais são os “Hints” utilizados por essa profile para influenciar o Otimizador na criação do plano de execução.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
SQL>@c:\temp\coe_xfr_sql_profile_arrf7tftg4pxg_330808811.sql;
SQL>REM
SQL>REM $Header: 215187.1 coe_xfr_sql_profile_arrf7tftg4pxg_330808811.sql 11.4.1.4 2016/03/27 csierra $
SQL>REM
SQL>REM Copyright (c) 2000-2010, Oracle Corporation. All rights reserved.
SQL>REM
SQL>REM AUTHOR
SQL>REM   carlos.sierra@oracle.com
SQL>REM
SQL>REM SCRIPT
SQL>REM   coe_xfr_sql_profile_arrf7tftg4pxg_330808811.sql
SQL>REM
SQL>REM DESCRIPTION
SQL>REM   This script is generated by coe_xfr_sql_profile.sql
SQL>REM   It contains the SQL*Plus commands to create a custom
SQL>REM   SQL Profile for SQL_ID arrf7tftg4pxg based on plan hash
SQL>REM   value 330808811.
SQL>REM   The custom SQL Profile to be created by this script
SQL>REM   will affect plans for SQL commands with signature
SQL>REM   matching the one for SQL Text below.
SQL>REM   Review SQL Text and adjust accordingly.
SQL>REM
SQL>REM PARAMETERS
SQL>REM   None.
SQL>REM
SQL>REM EXAMPLE
SQL>REM   SQL> START coe_xfr_sql_profile_arrf7tftg4pxg_330808811.sql;
SQL>REM
SQL>REM NOTES
SQL>REM   1. Should be run as SYSTEM or SYSDBA.
SQL>REM   2. User must have CREATE ANY SQL PROFILE privilege.
SQL>REM   3. SOURCE and TARGET systems can be the same or similar.
SQL>REM   4. To drop this custom SQL Profile after it has been created:
SQL>REM  EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('coe_arrf7tftg4pxg_330808811');
SQL>REM   5. Be aware that using DBMS_SQLTUNE requires a license
SQL>REM  for the Oracle Tuning Pack.
SQL>REM
SQL>WHENEVER SQLERROR EXIT SQL.SQLCODE;
SQL>REM
SQL>VAR signature NUMBER;
SQL>REM
SQL>DECLARE
  2  sql_txt CLOB;
  3  h       SYS.SQLPROF_ATTR;
  4  BEGIN
  5  sql_txt := q'[
  6  select col1, col2, col3 from tab01 where col1 = 77150
  7  ]'
;
  8  h := SYS.SQLPROF_ATTR(
  9  q'[BEGIN_OUTLINE_DATA]',
 10  q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
 11  q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
 12  q'[DB_VERSION('11.2.0.4')]',
 13  q'[ALL_ROWS]',
 14  q'[OUTLINE_LEAF(@"SEL$1")]',
 15  q'[INDEX_RS_ASC(@"SEL$1" "TAB01"@"SEL$1" ("TAB01"."COL1"))]',
 16  q'[END_OUTLINE_DATA]');
 17  :signature := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt);
 18  DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
 19  sql_text    => sql_txt,
 20  profile     => h,
 21  name        => 'coe_arrf7tftg4pxg_330808811',
 22  description => 'coe arrf7tftg4pxg 330808811 '||:signature||'',
 23  category    => 'DEFAULT',
 24  validate    => TRUE,
 25  replace     => TRUE,
 26  force_match => FALSE /* TRUE:FORCE (match even when different literals in SQL). FALSE:EXACT (similar to CURSOR_SHARING) */ );
 27  END;
 28  /

Procedimento PL/SQL concluído com sucesso.

SQL>WHENEVER SQLERROR CONTINUE
SQL>SET ECHO OFF;

            SIGNATURE
---------------------
  9480737169037303819


... manual custom SQL Profile has been created


COE_XFR_SQL_PROFILE_arrf7tftg4pxg_330808811 completed
SQL>
SQL> conn sys@lab11 as sysdba
Informe a senha:
Conectado.
SQL> @sql_profile_hints11;
Informe o valor para name: coe_arrf7tftg4pxg_330808811

HINT
----------------------------------------------------------------------------------------------------
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
DB_VERSION('11.2.0.4')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX_RS_ASC(@"SEL$1" "TAB01"@"SEL$1" ("TAB01"."COL1"))
END_OUTLINE_DATA

SQL>

 

Observando os “Hints” utilizados na profile gerada pelo script verificamos que eles dão instruções especificas para Otimizador produzir o plano de execução, tais como o Hint INDEX_RS_ASC que sugere ao Otimizador para utilizar a operação INDEX RANGE SCAN para acessar o índice TAB01_COL1.

Conclusão

A utilização de SQL Profile no processo de Tuning de consultas abre um leque de possibilidades, seja utilizando o SQL Tuning Advisor ou o script coe_xfr_sql_profile. Esse recurso agiliza o processo de Tuning pois não necessita de alteração no código da aplicação e o SQL Tuning Advisor ajuda no processo de Tuning pois ele tem condições de reparar aqueles planos de baixa qualidade produzidos pelo Otimizador que tem um tempo extremamente limitado para analisar e gerar um plano de execução para instrução SQL quando ela é submetida para execução no banco.

Scripts

Abaixo a lista o scripts utilizados nesse artigo: 

find_sql 

dplan

create_tuning_task

sql_profile_hints11

coe_xfr_sql_profile

Referências

http://kerryosborne.oracle-guy.com/2009/04/oracle-sql-profiles/

https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:22829633914543

https://carlos-sierra.net/2012/04/09/custom-sql-profile-and-plan-stability-on-10g/

http://docs.oracle.com/cd/E28271_01/server.1111/e16638/sql_tune.htm#i36634

 

Mídia social

 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios são marcados com *