O pacote DBMS_XPLAN fornece uma maneira fácil para exibir o plano de execução em vários formatos pré-definidos, essa flexibilidade e o nível de detalhes estatísticos que o pacote oferece o torna uma ferramenta imprescindível num processo de tuning de uma instrução SQL. Você pode usar o pacote para exibir uma…
SQL Profile: uma poderosa aliada no processo de Tuning
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 > |
.
Ajudo DBAs e analistas de sistema a se destacarem em suas empresas
e obter um crescimento mais acelerado em suas carreiras, quer saber mais click no link abaixo:
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:
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
1
Olá, de onde veio o nome da task? Preciso de alguma licença pra conseguir gerar?
tuning_arrf7tftg4pxg
SELECT DBMS_SQLTUNE.report_tuning_task(‘&&task_name’) AS recommendations FROM dual
Error report –
SQL Error: ORA-13605: The specified task or object xxxx does not exist for the current user.
Olá Jardel,
No artigo a task “tuning_arrf7tftg4pxg” é criada na execução do scripts “create_tuning_task.sql”.
Para utilizar a package DBMS_SQLTUNE do SQL Tuning Advisor (STA) você precisa ter a licença Enterprise Edition e as options DIAGNOSTIC & TUNING PACK.
Espero ter esclarecido sua dúvida.