Buscar

DicasSQL

Prévia do material em texto

Dicas para otimização de consultas
�
Índice
3Introdução	�
41. Método de Acesso	�
41.1 Full Table Scan	�
41.2 Table Access by Rowid	�
51.3 Index Scan	�
82. Tipos de Join	�
82.1 Nested Loops	�
92.2 Sort-Merge	�
102.3 Hash Join	�
112.5 Star Join	�
122.6 Star transformation	�
143. Hints	�
143.1 Tipo de Otimizador	�
143.2 Subquery / View	�
153.3 Acesso	�
163.4 Join	�
173.5 Parallel Query (PQ)	�
173.7 Variados	�
184. Dicas	�
194.1 Evitar função em coluna indexada	�
204.2 Join com colunas do mesmo tipo	�
224.3 Coletar as estatísticas com regularidade	�
244.4 Sql Trace	�
�
Introdução
Este documento tem o objetivo de auxiliar os desenvolvedores e dbas na otimização de consultas.
Inicialmente revisaremos alguns pontos importantes: os métodos de acesso, os algoritmos usados para realização do join e os hints usados para modificar o plano de execução das consultas.
Em seguida veremos algumas dicas para se aproveitar o máximo da eficiência deste banco de dados.
 �
1. Método de Acesso
Representa o tipo de acesso para obter os dados de uma determinada tabela. O Oracle possui os seguintes métodos: 
1.1 Full Table Scan
Realiza a leitura direta da tabela para determinar os registros que satisfazem a cláusula Where
Permite o uso do multiblock I/O (leitura de vários blocos seqüenciais com um simples I/O)
Permite a paralelizar ção
Nem sempre representa um método de acesso ruim
Representação no explain plan:
OPERATION OPTIONS OBJECT_NAME 
------------------------------ -------------------- ---------------
 0 SELECT STATEMENT .
 1 SORT AGGREGATE .
 2 TABLE ACCESS FULL TESTE.TAB_LOC
1.2 Table Access by Rowid
Realiza o acesso a tabela pelo Rowid
É a maneira mais rápida de acessar um registro
Representação no explain plan:
OPERATION OPTIONS OBJECT_NAME 
------------------------------ -------------------- -------------------
 0 SELECT STATEMENT .
 1 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC
 2 INDEX RANGE SCAN TESTE.TAB_LOC_DATA
�
1.3 Index Scan
Realiza o acesso aos dados através de um índice
A maioria é do tipo b*-tree (padrão)
Estrutura interna da B*-tree
Possui os seguintes tipos:
Unique Scan: é usado quando a tabela possui uma chave única ou primária. Retorna apenas 1 rowid.	
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- -------------------
 0 SELECT STATEMENT .
 1 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC
 2 INDEX UNIQUE SCAN TESTE.TAB_LOC_PK
Range Scan: é usado para obter um determinado intervalo de dados. Retorna 0 ou mais rowids.
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- --------------------
 0 SELECT STATEMENT .
 1 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC
 2 INDEX RANGE SCAN TESTE.TAB_LOC_DATA
Full Scan: é usado quando a query usa pelo menos uma coluna do índice. Também é usado quando a consulta não possui predicado e se deseja evitar a operação de sort.
Fast Full Scan: é um Full Table Scan alternativo usado quando o índice possui todas colunas necessárias para a query. Para ler todos dados do índice, é mais rápido que o Index Scan por possibilitar o Multiblock I/O e a paralelização. 
 Obs: não pode ser usado para evitar a operação de sort (os dados não são retornados de forma ordenada). 
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- -------------------
 0 SELECT STATEMENT .
 1 INDEX FAST FULL SCAN TESTE.TAB_LOC_DATA
Index Join: é um hash join com alguns índices da tabela. Juntos obtêm todas colunas referenciadas na query.
OPERATION OPTIONS OBJECT_NAME 
------------------------- ----------------- -----------------------
 0 SELECT STATEMENT .
 1 VIEW TESTE.index$_join$_001
 2 HASH JOIN .
 3 INDEX FAST FULL SCAN TESTE.TAB_LOC_DATA
 4 INDEX FAST FULL SCAN TESTE.TAB_LOC_PK
Bitmap: utiliza um bitmap como chave para cada valor distinto da coluna e uma função de mapeamento que converte cada bit para um rowid. Se a coluna indexada tiver baixa cardinalidade, são rápidos e ocupam pouco espaço.
 Obs: uma coluna é considerada de baixa cardinalidade se o número de valores distintos for menor ou igual a 1% do total de registros.
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- --------------------
 0 SELECT STATEMENT .
 1 TABLE ACCESS BY INDEX ROWID TESTE.VENDAS
 2 BITMAP CONVERSION TO ROWIDS .
 3 BITMAP INDEX SINGLE VALUE TESTE.VENDAS_TIPO_BM
�
Exemplo: tabela Customer com 6 registros
 
 
 
 Índice Bitmap sobre a coluna Region 
 
Consulta de clientes casados e da região central e oeste.
			SELECT COUNT(*) FROM customer
WHERE STATUS = 'married' 
 AND REGION IN ('central','west');
		
	 
�
2. Tipos de Join
O join é uma operação que permite combinar o resultado de duas ou mais tabelas baseando se nos valores das colunas em comum. O Oracle utiliza os seguintes algoritmos 
2.1 Nested Loops
O otimizador escolhe uma tabela para ser a outer table (driving table) e outra para ser a inner table
Para cada registro da outer table, o Oracle acha todos registros da inner table que satisfazem o join condition
O Oracle combina os dados de cada par de registros que satisfazem o join condition e então retorna os registros resultantes
select *
 from tab_loc l,
 tab_loc_peq p
 where l.codigo = p.codigo;
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- ------------------
 0 SELECT STATEMENT .
 1 NESTED LOOPS .
 2 TABLE ACCESS FULL TESTE.TAB_LOC_PEQ
 3 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC
 4 INDEX UNIQUE SCAN TESTE.TAB_LOC_PK
 
2.2 Sort-Merge
Os registros de cada tabela são ordenados pelas colunas do join condition
É feito um merge das duas ordenações e os registros que satisfizerem o join condition são retornados
select /*+ use_merge(l p) */ *
 from tab_loc l,
 tab_loc_peq p
 where l.codigo = p.codigo;
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- ----------------------
 0 SELECT STATEMENT .
 1 MERGE JOIN .
 2 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC_PEQ
 3 INDEX FULL SCAN TESTE.TAB_LOC_PEQ_PK
 4 SORT JOIN .
 5 TABLE ACCESS FULL TESTE.TAB_LOC
 
 
Obs: a etapa 2 não precisou realizar o sort porque o range scan já retornou os dados ordenados.
�
2.3 Hash Join
O Oracle escolhe uma tabela menor para construir a tabela hash e o maior para verificar a tabela hash
Geralmente o Hash Join é mais rápido que o Sort-Merge
select /*+ use_hash(l) */ *
 from tab_loc l,
 tab_loc_peq p
 where l.codigo = p.codigo;
OPERATION OPTIONS OBJECT_NAME 
------------------------- -------------------- --------------------
 0 SELECT STATEMENT.
 1 HASH JOIN .
 2 TABLE ACCESS FULL TESTE.TAB_LOC_PEQ
 3 TABLE ACCESS FULL TESTE.TAB_LOC
 
�
2.5 Star Join
Join realizado entre uma tabela fato e algumas dimensões (tabelas lookup com informações dos atributos da tabela fato)
Geralmente é usado quando o schema tem tabelas fato grandes e dimensões bem pequenas
Cada tabela lookup possui um join com a tabela fato (PK_Lookup = FK_Fato_Lookup), mas as tabelas lookups não têm join entre si.
Os joins são realizados nas seguintes etapas: 
produto cartesiano entre as dimensões 
join com a tabela fato usando um índice concatenado por nested loops
Exemplo de um star join
 
 
Não confunfir o start join com o star transformation
 �
2.6 Star transformation
Transformação de uma consulta realizada entre uma tabela fato e algumas dimensões 
É realizado apenas se houver redução no custo
Não há necessidade de criar índices concatenados para atender a combinação de tabelas referenciadas, pois combina índices bitmap da tabela fato
Pré-requisitos
- Deve existir um índice bitmap para cada FK
- STAR_TRANSFORMATION_ENABLED = TRUE
- CBO deve estar sendo usado
A consulta é realizada da em 2 fases:
O Oracle transforma a consulta e utiliza os índices bitmap das colunas FKs da tabela fato para obter o result set (conjunto exato dos registros necessários para avaliar a consulta). Em seguida os registros da tabela fato são obtidos.
O join entre a tabela fato e as dimensões é realizado. Geralmente o hash join é o mais eficiente.
Exemplo:
Comando original
Tabela fato: sales
Dimensões : store, time e product
SELECT store.sales_district,
 time.fiscal_period,
 SUM(sales.dollar_sales) revenue,
 SUM(dollar_sales) - SUM(dollar_cost) income
FROM sales, store, time, product
WHERE sales.store_key = store.store_key 
 AND sales.time_key = time.time_key 
 AND sales.product_key = product.product_key 
 AND time.fiscal_period IN ('3Q95', '4Q95', '1Q96') 
 AND product.department = 'Grocery' 
 AND store.sales_district IN ('San Francisco', 'Los Angeles')
GROUP BY store.sales_district, time.fiscal_period;
Transformação 
1ª parte: obtenção do result set
SELECT ... 
FROM sales
WHERE store_key IN (SELECT store_key FROM store 
 WHERE sales_district IN ('WEST','SOUTHWEST')) 
 AND time_key IN (SELECT time_key FROM time 
 WHERE quarter IN ('3Q96', '4Q96', '1Q97')) 
 AND product_key IN (SELECT product_key FROM product 
 WHERE department = 'GROCERY');
2ª parte: join entre o result set e as dimensões
�
Plano de execução
SELECT STATEMENT
 HASH JOIN
 HASH JOIN
 HASH JOIN
 TABLE ACCESS SALES BY INDEX ROWID
 BITMAP CONVERSION TO ROWIDS
 BITMAP AND
 BITMAP MERGE
 BITMAP KEY ITERATION
 TABLE ACCESS STORE FULL
 BITMAP INDEX SALES_STORE_KEY RANGE SCAN
 BITMAP MERGE
 BITMAP KEY ITERATION
 TABLE ACCESS TIME FULL
 BITMAP INDEX SALES_TIME_KEY RANGE SCAN
 BITMAP MERGE
 BITMAP KEY ITERATION
 TABLE ACCESS PRODUCTS FULL
 BITMAP INDEX SALES_PRODUCT_KEY RANGE SCAN
 TABLE ACCESS TIME FULL
 TABLE ACCESS PRODUCTS FULL
 TABLE ACCESS STORE FULL
�
3. Hints
Hint é um comentário padronizado que se inclui no meio do comando para modificar o plano de execução. Geralmente ele é utilizado nos casos em que o Oracle não consegue definir uma boa estratégia.
Sintaxe: 
 select /*+ Hint... */ 
 colunas ...
 from tabelas ...
Abaixo segue a listagem dos hints para consultas:
3.1 Tipo de Otimizador
	
All_rows – força o cost-based optimizer(CBO) a otimizar o comando para retornar todos registros com o menor tempo possível (maior throughput)
First_rows – força o CBO a otimizar o comando para obter o melhor tempo de resposta
Rule – força a utilização do rule-based optimizer(RBO) 
Choose – deixa para o Oracle optar por CBO ou RBO. Se pelo menos uma das tabelas possuir estatísticas coletadas então CBO é optado, senão é considerado o RBO.
3.2 Subquery / View
	
Push_Subq – executa as subqueries antes. Normalmente são executadas por último.
	Exemplo
 select /*+ push_subq */ 
 count(*)
 from tabela_teste
 where codigo in (select codigo 
 from tabela_teste2
 where tipo = ‘T’);
 
Merge(v) – força o merge da view com a query principal
	Exemplo
 select /*+ merge(v) */
 count(*)
 from view_teste v,
 tabela_teste t
 where v.codigo = t.codigo;
�
No_Merge(v) – previne o merge da view com a query principal
	Exemplo
 select /*+ no_merge(v) */ 
 count(*)
 from view_teste v,
 tabela_teste t
 where v.codigo = t.codigo;
 
Merge_Aj – transforma o NOT IN subquery em sort-merge anti-join
 
Hash_Aj – transforma o NOT IN subquery em hash anti-join
Merge_Sj - transforma o EXISTS em sort-merge semi-join mantendo a semântica. O default do EXISTS é usar o algoritmo nested loops. 
 Obs: nos casos em que a tabela que está sendo verificada (tabela dentro do EXISTS) não possuir índice nas colunas do join, haverá um ganho de performance se o sort-merge semi-join for usado.
Hash_Sj – transforma o EXISTS em hash semi-join mantendo a semântica. O default do EXISTS é usar o algoritmo nested loops.
 Obs: nos casos em que a tabela que está sendo verificada (tabela dentro do EXISTS) não possuir índice nas colunas do join, haverá um ganho de performance se o hash semi-join for usado.
Push_Join_Pred(v) – força a view usar o join predicate da query principal
3.3 Acesso
Full(tab) – força o full table scan para tabela ‘tab’
Cache(tab) – força que blocos retornados da consulta sejam colocados na lista LRU do buffer cache quando o full table scan for executado, se o tamanho da tabela for menor ou igual ao valor do parâmetro CACHE_SIZE_THRESHOLD.
Nocache(tab) – força que os blocos retornados da consulta não sejam colocados na cache, mesmo que a tabela tenha o parâmetro cache habilitado.
Rowid(tab) – força o acesso a tabela ‘tab’ pelo rowid
Index(tab index) – força o acesso a tabela ‘tab’ pelo índice ‘index’
Index_Asc(tab index) – induz o Oracle a acessar o índice ‘index’ da tabela ‘tab’ com um range scan
Index_Desc(tab index) – induz o Oracle a acessar o índice ‘index’ da tabela ‘tab’ na ordem decrescente
Ndex_Ffs(tab index) – opta pelo fast full scan ao invés do full table scan
Index_Combine(tab i1.. i5) – realiza a combinação booleana de índices bitmap com melhor custo.
Index_join(tab i1.. i5) – induz a utilização index join
And_Equal(tab i1.. i5) – realiza o merge de 2 a 5 índices com apenas 1 coluna.
Use_Concat – transforma a combinação de ORs/IN na cláusula WHERE em uma query composta com operador de conjunto UNION ALL. 
No_Expand – não permite a concatenação 
Driving_Site(tab) – a query é executada no site que a tabela ‘tab’ se encontra
	
3.4 Join
Use_Nl(tab) – induz o Oracle a optar a tabela ‘tab’ como sendo a inner table.
Use_Merge(tab) – induz o Oracle a realizar o join da tabela ‘tab’ com o método sort-merge.
Use_Hash(tab) – induz o Oracle a realizar o join da tabela ‘tab’ com o método hash join.
Star – induz o Oracle a realizar o start query
Star_Transformation – induz o Oracle a optar pelo melhor plano com Star Transformation. A transformação só é realizada se for benéfico.
Ordered – induz o Oracle a executar o join na ordem em que as tabelas se encontram na cláusula FROM (da esquerda para direita ede cima para baixo).
Leading(tab) - induz o Oracle iniciar o join com a tabela ‘tab’.
3.5 Parallel Query (PQ)
Parallel (tab,degree[,inst]) – induz o Oracle a paralelizar a consulta a tabela ‘tab’ pelo grau de paralelismo ‘degree’ com ‘inst’ instâncias.
Parallel_Index(table,[index,[degree[,inst]]]) - induz o oracle a paralelizar o acesso de índice particionado.
Pq_Distribute(tab,out,in)- indica como distribuir os registros da tabela ‘tab’ em uma PQ entre produtores e consumidores. Os valors para ‘out’ (outer table) e ‘in’ (inner table) podem ser: hash, none, broadcast ou partition.
Noparallel(tab) – evita a paralelização do acesso a tabela ‘tab’
Noparallel_Index(tab) – evita o parallel index scan
3.7 Variados
Rewrite(v1[,v2]) – permite que uma query compatível com a consulta de uma materialized view (v1,v2,...) seja reescrita de forma que aproveite os dados pré processados da materialized view.
	Obs: versão posterior a 8.1
Norewrite – não permite que a query seja reescrita
�
4. Dicas
	Abaixo seguem as tabelas que usaremos nos exemplos.
 tab_loc: tabela local
índices : tab_loc_pk (codigo)
 tab_loc_ind (data )
registros: 500.000 
SQL> desc tab_loc
 Name Null? Type
 ------------------------ -------- --------------
 CODIGO NOT NULL VARCHAR2(10)
 DESCRICAO NOT NULL VARCHAR2(50)
 DATA NOT NULL DATE
 VALOR NOT NULL NUMBER
 tab_loc_peq: tabela local pequena
índices : tab_loc_peq_pk (codigo)
registros: 50 
SQL> desc tab_loc_peq
 Name Null? Type
 ------------------------ -------- --------------
 CODIGO NOT NULL VARCHAR2(10)
 DESCRICAO NOT NULL VARCHAR2(50)
 DATA NOT NULL DATE
 VALOR NOT NULL NUMBER
 tab_loc_gra: tabela local grande
índices : tab_loc_gra_pk (codigo)
registros: 3.070.307
SQL> desc tab_loc_peq
 Name Null? Type
 ------------------------ -------- --------------
 CODIGO NOT NULL NUMBER(10)
 DESCRICAO NOT NULL VARCHAR2(50)
 DATA NOT NULL DATE
 VALOR NOT NULL NUMBER
 tab_rem@link_bci: tabela remota
índices : tab_rem_pk (codigo)
registros: 500.000
SQL> desc tab_rem@link_bci
 Name Null? Type
 ------------------------ -------- ------------
 CODIGO NOT NULL VARCHAR2(10)
 DESCRICAO NOT NULL VARCHAR2(50)
 DATA NOT NULL DATE
 VALOR NOT NULL NUMBER
�
4.1 Evitar função em coluna indexada
Exemplo: consultar todos registros de um determinado dia
Consulta ineficiente
 select count(*)
 from tab_loc
 where trunc(data) = to_date(‘10/10/2003’,‘dd/mm/yyyy’);
Resultado
 Tempo: 2,5s
 OPERATION OPTIONS OBJECT_NAME 
 ------------------------------ -------------------- ------------------
 0 SELECT STATEMENT .
 1 SORT AGGREGATE .
 2 INDEX FAST FULL SCAN TESTE.TAB_LOC_DATA
 Statistics
 ---------------------------------------------------
 0 recursive calls
 6 db block gets
 1196 consistent gets
 1196 physical reads
 0 redo size
 205 bytes sent via SQL*Net to client
 261 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 1 sorts (memory)
 0 sorts (disk)
 1 rows processed
Consulta eficiente
 select count(*)	
 from tab_loc
 where data >= to_date(‘10/10/2003’,‘dd/mm/yyyy’)
 and data < to_date(‘10/10/2003’,‘dd/mm/yyyy’) + 1;
Resultado
 Tempo: 0,1s
 OPERATION OPTIONS OBJECT_NAME 
 ------------------------------ -------------------- ------------------
 0 SELECT STATEMENT .
 1 SORT AGGREGATE .
 2 INDEX RANGE SCAN TESTE.TAB_LOC_DATA
 Statistics
 ---------------------------------------------------
 0 recursive calls
 0 db block gets
 3 consistent gets
 0 physical reads
 0 redo size
 205 bytes sent via SQL*Net to client
 310 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 1 sorts (memory)
 0 sorts (disk)
 1 rows processed
�
4.2 Join com colunas do mesmo tipo
Se isto for inevitável, converta (aplique uma função to_char, to_number, to_date,...) no lado do join que não prejudique o plano de execução. A conversão implícita é custosa, além de ter o mesmo efeito que a utilização de funções em campos indexados.
Consulta ineficiente
 select count(*)
 from tab_loc l,
 tab_loc_gra g
 where l.codigo = g.codigo /* l.codigo é VARCHAR2 e g.codigo é NUMBER */
 and g.data = to_date('10/10/2003','dd/mm/yyyy');
Resultado
 Tempo: 1s
 OPERATION OPTIONS OBJECT_NAME 
 ------------------------------ -------------------- ----------------------
 0 SELECT STATEMENT .
 1 HASH JOIN .
 2 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC_GRA
 3 INDEX RANGE SCAN TESTE.TAB_LOC_GRA_DATA
 4 TABLE ACCESS FULL TESTE.TAB_LOC
 Statistics
 ---------------------------------------------------
 0 recursive calls
 4 db block gets
 1061 consistent gets
 0 physical reads
 0 redo size
 207 bytes sent via SQL*Net to client
 378 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 0 sorts (memory)
 0 sorts (disk)
 1 rows processed
Inclusão da conversão explícita de tipo
 
 select count(*)
 from tab_loc_gra g,
 tab_loc l
 where l.codigo = to_char(g.codigo,'fm99999999') /* ambos VARCHAR2 */
 and g.data = to_date('10/10/2003','dd/mm/yyyy');
Resultado
 Tempo: 0,4s
Obs: Apenas incluindo a conversão de tipo, o tempo foi reduzido pela metade. Note que o plano de execução não foi alterado.
�
 OPERATION OPTIONS OBJECT_NAME 
 ------------------------------ -------------------- -----------------------
 0 SELECT STATEMENT .
 1 SORT AGGREGATE .
 2 HASH JOIN .
 3 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC_GRA
 4 INDEX RANGE SCAN TESTE.TAB_LOC_GRA_DATA
 5 INDEX FAST FULL SCAN TESTE.TAB_LOC_PK
 Statistics
 -----------------------------------------------------
 0 recursive calls
 4 db block gets
 1061 consistent gets
 0 physical reads
 0 redo size
 206 bytes sent via SQL*Net to client
 360 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 0 sorts (memory)
 0 sorts (disk)
 1 rows processed
Consulta incluindo a conversão de tipo e Hints
 select /*+ ordered use_nl(l) */ count(*)
 from tab_loc_gra g,
 tab_loc l
 where l.codigo = to_char(g.codigo,'fm9999999') /* ambos c/ tipo VARCHAR2 */
 and g.data = to_date('10/10/2003','dd/mm/yyyy');
Resultado
 Tempo: 0,01s
 OPERATION OPTIONSOBJECT_NAME 
 ---------------------------- -------------------- -------------------- 
 0 SELECT STATEMENT .
 1 SORT AGGREGATE .
 2 NESTED LOOPS .
 3 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC_GRA
 4 INDEX RANGE SCAN TESTE.TAB_LOC_GRA_DATA
 5 INDEX UNIQUE SCAN TESTE.TAB_LOC_PK
 Statistics
 ---------------------------------------------------
 0 recursive calls
 0 db block gets
 39 consistent gets
 0 physical reads
 0 redo size
 206 bytes sent via SQL*Net to client
 407 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 0 sorts (memory)
 0 sorts (disk)
 1 rows processed
�
4.3 Coletar as estatísticas com regularidade
Utilize o comando Analyze ou a package Dbms_stats
	Consulta sem anlyze
 analyze table tab_loc delete statistics
 analyze table tab_loc_peq delete statistics
 select l.*
 from tab_loc l,
 tab_loc_peq d,
 tab_rem@link_bci r
 where l.codigo = r.codigo
 and l.codigo = d.codigo
Resultado
 Tempo: 18s
 OPERATION OPTIONS OBJECT_NAME 
 ------------------------------ -------------------- -----------------------
 0 SELECT STATEMENT .
 1 NESTED LOOPS .
 2 NESTED LOOPS .
 3 REMOTE . 
 4 TABLE ACCESS BY INDEX ROWID TESTE.TAB_LOC
 5 INDEX UNIQUE SCAN TESTE.TAB_LOC_PK
 6 INDEX UNIQUE SCAN TESTE.TAB_LOC_PEQ_PK
 ID OTHER
 -- ------------------------------------------------------------------------
 3 SELECT "CODIGO" FROM "TAB_REM" "R"
 Statistics
 -----------------------------------------------------
 7 recursive calls
 6 db block gets
 1999953 consistent gets
 0 physical reads
 172 redo size
 191 bytes sent via SQL*Net to client
 332 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 0 sorts (memory)
 0 sorts (disk)
 1 rows processed
�
	Consulta com analyze
 analyze table tab_loc compute statistics;
 analyze table tab_loc_peq compute statistics;
 select l.*
 from tab_loc l,
 tab_loc_peq d,
 tab_rem@link_bci r
 where l.codigo = r.codigo
 and l.codigo = d.codigo;
Resultado
 Tempo: 0.1s
 OPERATION OPTIONS OBJECT_NAME 
 ------------------------------ -------------------- ---------------------
 0 SELECT STATEMENT .
 1 SORT AGGREGATE .
 2 NESTED LOOPS .
 3 NESTED LOOPS .
 4 INDEX FULL SCAN TESTE.TAB_LOC_PEQ_PK
 5 INDEX UNIQUE SCAN TESTE.TAB_LOC_PK
 6 REMOTE . 
 ID OTHER
 -- ----------------------------------------------------------------------
 6 SELECT "CODIGO" FROM "TAB_REM" "R" WHERE :1="CODIGO"
 Statistics
 ----------------------------------------------------
 0 recursive calls
 0 db block gets
 151 consistent gets
 0 physical reads
 0 redo size
 207 bytes sent via SQL*Net to client
 332 bytes received via SQL*Net from client
 3 SQL*Net roundtrips to/from client
 0 sorts (memory)
 0 sorts (disk)
 1 rows processed
�
4.4 Sql Trace 
	
Utilize o sql trace para identificar comandos ineficientes de uma determinada sessão. 
1º) Ative o timed_statistics
alter system set timed_statistics=true;
2º) Ative o trace
Se for a própria sessão execute:
 	alter session set sql_trace=true;
Se for outra sessão execute:
	exec sys.dbms_system.set_sql_trace_in_session(<sid>,< serial#>,true);
3º) Depois de um certo tempo desative o trace
Se for a própria sessão execute:
 	alter session set sql_trace=false;
Se for outra sessão execute:
	exec sys.dbms_system.set_sql_trace_in_session(<sid>,< serial#>,false);
4º) Desative o timed_statistics
alter system set timed_statistics=false;
5º) Localize o trace gerado (sempre no servidor)
Os traces serão gerados no diretório definido para o parâmetro USER_DUMP_DEST. Para identificá-lo execute:
select value 
 from v$parameter 
 where name = 'user_dump_dest';
O nome do arquivo pode ser obtido com o sguinte comando:
select 'ora_'||spid||'_'||lower(i.instance_name)||'.trc' arquivo
 from v$process p,
 v$session s,
 v$instance i
where p.addr = s.paddr
 and s.sid = <sid>;
�
6º) Formate o arquivo trace com o tkprof.
tkprof arq_trace arq_saida explain=usuário/senha sys=no sort=opção
 arq_trace – nome do arquivo trace
 arq_saida – nome do arquivo de saída (formatado)
 opção - pode ser qualquer um dos valores abaixo:
 prscnt number of times parse was called
 prscpu cpu time parsing
 prsela elapsed time parsing
 prsdsk number of disk reads during parse
 prsqry number of buffers for consistent read during parse
 prscu number of buffers for current read during parse
 prsmis number of misses in library cache during parse
 execnt number of execute was called
 execpu cpu time spent executing
 exeela elapsed time executing
 exedsk number of disk reads during execute
 exeqry number of buffers for consistent read during execute
 execu number of buffers for current read during execute
 exerow number of rows processed during execute
 exemis number of library cache misses during execute
 fchcnt number of times fetch was called
 fchcpu cpu time spent fetching
 fchela elapsed time fetching
 fchdsk number of disk reads during fetch
 fchqry number of buffers for consistent read during fetch
 fchcu number of buffers for current read during fetch
 fchrow number of rows fetched
 userid userid of user that parsed the cursor
		
Exemplo: formatar o trace de forma que os comandos estejam ordenados pelo tempo gasto no fetch.
 tkprof ora_33_mig.trc saida.txt explain=usr/usr sys=no sort=fchela

Continue navegando