SQL Plan Management: como aceitar planos não recomendados
Fala pessoal! Hoje vou demonstrar aqui como podemos estar aceitando um plano de execução que não foi recomendado pela Evolve Advisor do SQL Plan Management.
O que é o SQL Plan Management?
Como não falei ainda sobre essa ferramenta aqui no blog, acredito que devo fazer as devidas apresentações.
O SQL Plan Management (SPM) é uma ferramenta do Oracle Database que tem como objetivo impedir regressões de performance em queries devido à alteração de planos de execução. Ele também pode verificar se existe um novo plano de execução possível, com maior performance, e automaticamente passar a utilizá-lo. Para manter essa dinâmica, o SPM realiza o gerenciamento dos planos de execução através de uma baseline, que abrange os planos de execução de um determinado SQL.
A baseline é criada durante uma captura inicial dos planos de execução, para SQLs que são executados duas vezes ou mais durante o período que a captura está habilitada (sendo assim considerado um “repeatable statement”). Essa captura pode ser feita alterando o parâmetro OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES para TRUE. A utilização das baselines no banco é controlada pelo parâmetro OPTIMIZER_USE_SQL_PLAN_BASELINES, que por padrão tem seu valor setado para TRUE.
Para que um plano de execução passe a ser utilizado, quando a utilização de baselines está habilitada, o plano precisa ser aceito na baseline. Esse aceite ocorre utilizando uma evolve task que analisa a melhoria de performance de novos planos de execução em relação aos planos já aceitos. A aceitação de um plano de execução pode ser feita automaticamente pelo Oracle, através de uma auto task que roda na janela de manutenção, ou manualmente.
Botando a mão na massa
Para a demonstração de um cenário onde a Evolve Task não aceita um novo plano de execução vamos utilizar as mesmas tabelas criadas no artigo “Adaptative Cursor Sharing: Ilustrado na prática” (caso você não tenha lido, pode acessá-lo aqui).
Inicialmente vamos habilitar a captura dos planos de execução através do parâmetro OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES, fazendo com que uma baseline seja criada para o SQL ID “d39fqfawqv2k1”:
SQL> conn hr/hr@pdb
Connected.
SQL> ALTER SESSION SET optimizer_capture_sql_plan_baselines=TRUE;
Session altered.
SQL> VARIABLE desc1 VARCHAR2(1);
SQL> VARIABLE desc2 VARCHAR2(1);
SQL> EXEC :desc1 := 'A'
PL/SQL procedure successfully completed.
SQL> EXEC :desc2 := 'A'
PL/SQL procedure successfully completed.
SQL> SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID
WHERE T1_DESC = :desc1 AND T2_DESC = :desc2; 2
COUNT(*)
----------
330000
SQL> SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID
WHERE T1_DESC = :desc1 AND T2_DESC = :desc2; 2
COUNT(*)
----------
330000
SQL> SET LINES WINDOW
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);SQL>
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
SQL_ID d39fqfawqv2k1, child number 0
-------------------------------------
SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID WHERE T1_DESC =
:desc1 AND T2_DESC = :desc2
Plan hash value: 4274056747
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 3035 (100)| |
| 1 | SORT AGGREGATE | | 1 | 40 | | | |
|* 2 | HASH JOIN | | 536K| 20M| 16M| 3035 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| T2 | 536K| 10M| | 656 (2)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 709K| 13M| | 486 (2)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."T1_ID"="T2"."T1_ID")
3 - filter("T2"."T2_DESC"=:DESC2)
4 - filter("T1"."T1_DESC"=:DESC1)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- SQL plan baseline SQL_PLAN_f519w123f6cdx27129147 used for this statement
29 rows selected.
SQL> ALTER SESSION SET optimizer_capture_sql_plan_baselines=FALSE;
Session altered.
Aqui fizemos duas execuções do SQL para que ele seja considerado um “repeatable statement”, e seja elegível para captura para criação da baseline. Aqui estamos usando valores para as bind variables que tem uma baixa seletividade, fazendo com que ocorram TABLE ACCESS FULL no plano de execução.
Após as duas execuções da query, uma baseline foi criada, e o plano atual foi adicionado à ela, como aceito:
SQL> COL PLAN_NAME FOR A50 SQL> COL ACCEPTED FOR A8 SQL> COL ENABLED FOR A8 SQL> SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE SIGNATURE IN (SELECT EXACT_MATCHING_SIGNATURE FROM V$SQL WHERE SQL_ID='d39fqfawqv2k1');SQL> SQL> SQL> 2 3 SQL_HANDLE PLAN_NAME ENABLED ACCEPTED ------------------------------ -------------------------------------------------- -------- -------- SQL_e2853c0886e331bd SQL_PLAN_f519w123f6cdx27129147 YES YES
Agora, vamos fazer uma execução alterando as bind variables, utilizando valores com baixa seletividade:
SQL> EXEC :desc1 := 'D'
PL/SQL procedure successfully completed.
SQL> EXEC :desc2 := 'D'
PL/SQL procedure successfully completed.
SQL> SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID
WHERE T1_DESC = :desc1 AND T2_DESC = :desc2; 2
COUNT(*)
----------
10000
SQL> SET LINES WINDOW
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
SQL_ID d39fqfawqv2k1, child number 1
An uncaught error happened in prepare_sql_statement : ORA-01403: no data found
NOTE: cannot fetch plan for SQL_ID: d39fqfawqv2k1, CHILD_NUMBER: 1
Please verify value of SQL_ID and CHILD_NUMBER;
It could also be that the plan is no longer in cursor cache (check v$sql_plan)
8 rows selected.
Ao tentarmos visualizar as informações do plano de execução, temos um erro, falando que o plano não pode ser encontrado. Isso ocorre porque o plano que o otimizador tentou utilizar não pertence à baseline. Caso façamos a retentativa temos:
SQL> SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID
WHERE T1_DESC = :desc1 AND T2_DESC = :desc2; 2
COUNT(*)
----------
10000
SQL> SET LINES WINDOW
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
SQL_ID d39fqfawqv2k1, child number 0
-------------------------------------
SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID WHERE T1_DESC =
:desc1 AND T2_DESC = :desc2
Plan hash value: 4274056747
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 1419 (100)| |
| 1 | SORT AGGREGATE | | 1 | 40 | | | |
|* 2 | HASH JOIN | | 84315 | 3293K| 3056K| 1419 (2)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| T2 | 97788 | 1909K| | 656 (2)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 84316 | 1646K| | 486 (2)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."T1_ID"="T2"."T1_ID")
3 - filter("T2"."T2_DESC"=:DESC2)
4 - filter("T1"."T1_DESC"=:DESC1)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- SQL plan baseline SQL_PLAN_f519w123f6cdx27129147 used for this statement
29 rows selected.
Podemos notar que nesta execução o child cursor utilizado foi o de número 0 (zero) enquanto que na primeira tentativa, onde o plano não foi exibido, o child cursor era o de número 1. Além disso, nessa execução ainda estamos fazendo o TABLE ACCESS FULL, mesmo tendo um índice nesta tabela que poderia ser utilizado para a consulta (a criação do índice foi mostrada no artigo referenciado anteriormente). Isso acontece porque este é o único plano aceito para esta baseline. Podemos verificar a view DBA_SQL_PLAN_BASELINES e verificar que agora temos um novo plano na baseline, mas ele ainda não foi aceito:
SQL> SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE SIGNATURE IN (SELECT EXACT_MATCHING_SIGNATURE FROM V$SQL WHERE SQL_ID='d39fqfawqv2k1'); SQL_HANDLE PLAN_NAME ENABLED ACCEPTED ------------------------------ -------------------------------------------------- -------- -------- SQL_e2853c0886e331bd SQL_PLAN_f519w123f6cdx27129147 YES YES SQL_e2853c0886e331bd SQL_PLAN_f519w123f6cdx50fc8be8 YES NO
Outra análise que pode ser feita é através da package DBMS_XPLAN, buscando os planos da baseline:
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(sql_handle => 'SQL_e2853c0886e331bd'));
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SQL handle: SQL_e2853c0886e331bd
SQL text: SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID WHERE T1_DESC
= :desc1 AND T2_DESC = :desc2
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Plan name: SQL_PLAN_f519w123f6cdx27129147 Plan id: 655528263
Enabled: YES Fixed: NO Accepted: YES Origin: AUTO-CAPTURE
Plan rows: From dictionary
--------------------------------------------------------------------------------
Plan hash value: 4274056747
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 40 | | 3035 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 40 | | | |
|* 2 | HASH JOIN | | 536K| 20M| 16M| 3035 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| T2 | 536K| 10M| | 656 (2)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 709K| 13M| | 486 (2)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."T1_ID"="T2"."T1_ID")
3 - filter("T2"."T2_DESC"=:DESC2)
4 - filter("T1"."T1_DESC"=:DESC1)
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- this is an adaptive plan
--------------------------------------------------------------------------------
Plan name: SQL_PLAN_f519w123f6cdx50fc8be8 Plan id: 1358728168
Enabled: YES Fixed: NO Accepted: NO Origin: AUTO-CAPTURE
Plan rows: From dictionary
--------------------------------------------------------------------------------
Plan hash value: 258474461
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 40 | | 1207 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 40 | | | |
|* 2 | HASH JOIN | | 84315 | 3293K| 2640K| 1207 (1)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 84316 | 1646K| | 274 (1)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IDX_01 | 84316 | | | 146 (1)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | T2 | 97788 | 1909K| | 656 (2)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."T1_ID"="T2"."T1_ID")
4 - access("T1"."T1_DESC"=:DESC1)
5 - filter("T2"."T2_DESC"=:DESC2)
Note
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
-----
- dynamic statistics used: dynamic sampling (level=2)
66 rows selected.
Como precisamos aceitar o segundo plano para que ele passe a ser utilizado, vamos criar uma evolve task manualmente, para analisarmos o report gerado:
-- criando a task
SQL> VARIABLE ev_task VARCHAR2(50);
SQL> EXECUTE :ev_task := DBMS_SPM.CREATE_EVOLVE_TASK(sql_handle => 'SQL_e2853c0886e331bd',plan_name => 'SQL_PLAN_f519w123f6cdx50fc8be8');
PL/SQL procedure successfully completed.
SQL> SELECT :ev_task FROM DUAL;
:EV_TASK
----------------------------------------------------------------------------------------------------------------------------------------------
TASK_22
-- executando a task
SQL> VARIABLE ev_exec VARCHAR2(50);
SQL> EXECUTE :ev_exec := DBMS_SPM.EXECUTE_EVOLVE_TASK(task_name => :ev_task);
PL/SQL procedure successfully completed.
SQL> SELECT :ev_exec FROM DUAL;
:EV_EXEC
----------------------------------------------------------------------------------------------------------------------------------------------
EXEC_52
-- gerando o report
SQL> VARIABLE ev_report CLOB;
SQL> EXECUTE :ev_report := DBMS_SPM.REPORT_EVOLVE_TASK(task_name => :ev_task, execution_name => :ev_exec);
PL/SQL procedure successfully completed.
-- mostrando o report gerado
SQL> SET LONG 9999
SQL> SELECT :ev_report FROM DUAL;
:EV_REPORT
--------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
--------------------------------------------------------------------------------
-------------
Task Information:
---------------------------------------------
Task Name : TASK_22
Task Owner : HR
Execution Name : EXEC_52
Execution Type : SPM EVOLVE
Scope : COMPREHENSIVE
Status : COMPLETED
Started : 03/17/2025 20:54:25
Finished : 03/17/2025 20:54:25
Last Updated : 03/17/2025 20:54:25
Global Time Limit : 2147483646
Per-Plan Time Limit : UNUSED
Number of Errors : 0
--------------------------------------------------------------------------------
-------------
SUMMARY SECTION
--------------------------------------------------------------------------------
-------------
Number of plans processed : 1
Number of findings : 1
Number of recommendations : 0
Number of errors : 0
--------------------------------------------------------------------------------
-------------
DETAILS SECTION
:EV_REPORT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-------------
Object ID : 2
Test Plan Name : SQL_PLAN_f519w123f6cdx50fc8be8
Base Plan Name : SQL_PLAN_f519w123f6cdx27129147
SQL Handle : SQL_e2853c0886e331bd
Parsing Schema : HR
Test Plan Creator : HR
SQL Text : SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID
WHERE T1_DESC = :desc1 AND T2_DESC = :desc2
Bind Variables:
-----------------------------
1 - (VARCHAR2(32)): D
2 - (VARCHAR2(32)): D
Execution Statistics:
-----------------------------
Base Plan Test Plan
---------------------------- ----------------------------
Elapsed Time (s): .002967 .002578
CPU Time (s): .002999 .002555
:EV_REPORT
--------------------------------------------------------------------------------
Buffer Gets: 409 274
Optimizer Cost: 1419 1207
Disk Reads: 0 0
Direct Writes: 0 0
Rows Processed: 0 0
Executions: 10 10
FINDINGS SECTION
--------------------------------------------------------------------------------
-------------
Findings (1):
-----------------------------
1. The plan was verified in 0.57700 seconds. It failed the benefit criterion
because its verified performance was only 1.49350 times better than that of
the baseline plan.
EXPLAIN PLANS SECTION
--------------------------------------------------------------------------------
-------------
Baseline Plan
-----------------------------
Plan Id : 103
Plan Hash Value : 655528263
--------------------------------------------------------------------------
:EV_REPORT
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 40 | 1419 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 40 | | |
| * 2 | HASH JOIN | | 84315 | 3372600 | 1419 | 00:00:01 |
| * 3 | TABLE ACCESS FULL | T2 | 97788 | 1955760 | 656 | 00:00:01 |
| * 4 | TABLE ACCESS FULL | T1 | 84316 | 1686320 | 486 | 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("T1"."T1_ID"="T2"."T1_ID")
* 3 - filter("T2"."T2_DESC"=:DESC2)
* 4 - filter("T1"."T1_DESC"=:DESC1)
Notes
-----
- Dynamic sampling used for this statement ( level = 2 )
Test Plan
-----------------------------
Plan Id : 104
Plan Hash Value : 1358728168
--------------------------------------------------------------------------------
--------------
| Id | Operation | Name | Rows | Bytes | Cos
t | Time |
--------------------------------------------------------------------------------
--------------
:EV_REPORT
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 40 | 120
7 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 40 |
| |
| * 2 | HASH JOIN | | 84315 | 3372600 | 120
7 | 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 84316 | 1686320 | 27
4 | 00:00:01 |
| * 4 | INDEX RANGE SCAN | IDX_01 | 84316 | | 14
6 | 00:00:01 |
| * 5 | TABLE ACCESS FULL | T2 | 97788 | 1955760 | 65
6 | 00:00:01 |
--------------------------------------------------------------------------------
--------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("T1"."T1_ID"="T2"."T1_ID")
* 4 - access("T1"."T1_DESC"=:DESC1)
* 5 - filter("T2"."T2_DESC"=:DESC2)
Notes
-----
- Dynamic sampling used for this statement ( level = 2 )
--------------------------------------------------------------------------------
-------------
Na comparação das estatísticas de execução dos dois planos, temos diversas melhorias, como o CPU Time, Elapsed Time, custo e Buffer Gets:
Execution Statistics:
-----------------------------
Base Plan Test Plan
---------------------------- ----------------------------
Elapsed Time (s): .002967 .002578
CPU Time (s): .002999 .002555
:EV_REPORT
--------------------------------------------------------------------------------
Buffer Gets: 409 274
Optimizer Cost: 1419 1207
Disk Reads: 0 0
Direct Writes: 0 0
Rows Processed: 0 0
Executions: 10 10
Mas mesmo com essas melhorias, temos a mensagem na seção “Findings” dizendo que o plano falhou no critério de melhoria de performance:
Findings (1):
-----------------------------
1. The plan was verified in 0.57700 seconds. It failed the benefit criterion
because its verified performance was only 1.49350 times better than that of
the baseline plan.
A verdade é que aqui batemos na trave. Caso o valor da melhoria de performance fosse acima de 1.5, teríamos o plano sendo recomendado para aceitação pelo report. Como o número de recomendações foi zero, caso a implementação das recomendações seja feita, nada será aplicado, como esperado:
SQL> VARIABLE acpt NUMBER;
SQL> EXECUTE :acpt := DBMS_SPM.IMPLEMENT_EVOLVE_TASK(task_name=>:ev_task, execution_name=>:ev_exec);
PL/SQL procedure successfully completed.
SQL> SELECT :acpt aceites FROM DUAL;
ACEITES
----------
0
Como aceitar um plano não recomendado?
Aqui como a evolve task não fez a recomendação, precisamos utilizar a procedure ACCEPT_SQL_PLAN_BASELINE da package DBMS_SPM. Para isso, passamos a evolve task criada anteriormente, e qual o Object ID do plano que desejamos aceitar (o valor pode ser visto no report gerado anteriormente):
SQL> BEGIN
DBMS_SPM.ACCEPT_SQL_PLAN_BASELINE(
task_name => :ev_task,
object_id => 2
);
END;
/ 2 3 4 5 6 7
BEGIN
*
ERROR at line 1:
ORA-38149: There is no recommended action for object 2 in task TASK_22.
ORA-06512: at "SYS.DBMS_SPM_INTERNAL", line 3974
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 95
ORA-06512: at "SYS.DBMS_SPM_INTERNAL", line 3932
ORA-06512: at "SYS.DBMS_SPM", line 3124
ORA-06512: at line 2
Bom, tomamos um ORA-38149, dizendo que não há recomendação para esse Object ID na task repassada. E de fato não há, como visto anteriormente. O pulo do gato aqui está em usar a opção “force” igual a “true“:
SQL> BEGIN
DBMS_SPM.ACCEPT_SQL_PLAN_BASELINE(
task_name => :ev_task,
object_id => 2,
force => true
);
END;
/ 2 3 4 5 6 7 8
PL/SQL procedure successfully completed.
Agora sim, nosso novo plano foi aceito e passa a ser utilizado na query, quando utilizamos as bind variables com valores de baixa seletividade:
SQL> SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED
FROM DBA_SQL_PLAN_BASELINES
WHERE SIGNATURE IN (SELECT EXACT_MATCHING_SIGNATURE FROM V$SQL WHERE SQL_ID='d39fqfawqv2k1'); 2 3
SQL_HANDLE PLAN_NAME ENABLED ACCEPTED
------------------------------ -------------------------------------------------- -------- --------
SQL_e2853c0886e331bd SQL_PLAN_f519w123f6cdx27129147 YES YES
SQL_e2853c0886e331bd SQL_PLAN_f519w123f6cdx50fc8be8 YES YES
SQL> alter system flush shared_pool;
System altered.
SQL> EXEC :desc1 := 'D'
PL/SQL procedure successfully completed.
SQL> EXEC :desc2 := 'D'
PL/SQL procedure successfully completed.
SQL> SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID
WHERE T1_DESC = :desc1 AND T2_DESC = :desc2; 2
COUNT(*)
----------
10000
SQL> SET LINES WINDOW
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);SQL> SQL>
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID d39fqfawqv2k1, child number 0
-------------------------------------
SELECT COUNT(*) FROM T1 JOIN T2 ON T1.T1_ID = T2.T1_ID WHERE T1_DESC =
:desc1 AND T2_DESC = :desc2
Plan hash value: 258474461
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 1207 (100)| |
| 1 | SORT AGGREGATE | | 1 | 40 | | | |
|* 2 | HASH JOIN | | 84315 | 3293K| 2640K| 1207 (1)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 84316 | 1646K| | 274 (1)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IDX_01 | 84316 | | | 146 (1)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | T2 | 97788 | 1909K| | 656 (2)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."T1_ID"="T2"."T1_ID")
4 - access("T1"."T1_DESC"=:DESC1)
5 - filter("T2"."T2_DESC"=:DESC2)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- SQL plan baseline SQL_PLAN_f519w123f6cdx50fc8be8 used for this statement
30 rows selected.
Conclusão
Sair por aí aceitando planos que não foram recomendados pelo Evolve Advisor do SQL Plan Management definitivamente não é uma boa ideia, exceto em casos como este, onde o benefício de performance existe, e está beirando o threshold de 1.5. É sempre bom lembrar que devemos fazer uma análise do report, olhando as estatísticas de execução, para que essa decisão seja tomada.
Abaixo o material que serviu de referência para a construção deste artigo:
Espero que tenham gostado e até o próximo post!
Publicar comentário