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