Professional Documents
Culture Documents
ndice Introduo.......................................................................................................................3 1. Mtodo de Acesso......................................................................................................4 1.1 Full Table Scan.....................................................................................................4 1.2 Table Access by Rowid........................................................................................4 1.3 Index Scan............................................................................................................5 2. Tipos de Join..............................................................................................................8 2.1 Nested Loops........................................................................................................8 2.2 Sort-Merge...........................................................................................................9 2.3 Hash Join............................................................................................................10 2.5 Star Join..............................................................................................................11 2.6 Star transformation.............................................................................................12 3. Hints.........................................................................................................................14 3.1 Tipo de Otimizador............................................................................................14 3.2 Subquery / View.................................................................................................14 3.3 Acesso................................................................................................................15 3.4 Join.....................................................................................................................16 3.5 Parallel Query (PQ)............................................................................................17 3.7 Variados.............................................................................................................17 4. Dicas.........................................................................................................................18 4.1 Evitar funo em coluna indexada.....................................................................19 4.2 Join com colunas do mesmo tipo.......................................................................20 4.3 Coletar as estatsticas com regularidade.............................................................22 4.4 Sql Trace ...........................................................................................................24
Introduo
Este documento tem o objetivo de auxiliar os desenvolvedores e dbas na otimizao de consultas. Inicialmente revisaremos alguns pontos importantes: os mtodos de acesso, os algoritmos usados para realizao do join e os hints usados para modificar o plano de execuo das consultas. Em seguida veremos algumas dicas para se aproveitar o mximo da eficincia deste banco de dados.
1. Mtodo de Acesso
Representa o tipo de acesso para obter os dados de determinada tabela. O Oracle possui os seguintes mtodos: uma
Permite o uso do multiblock I/O (leitura de vrios blocos seqenciais com um simples I/O) Permite a paralelizao Nem sempre representa um mtodo de acesso ruim
Possui os seguintes tipos: Unique Scan: usado quando a tabela possui uma chave nica ou primria. Retorna apenas 1 rowid.
OPERATION ------------------------0 SELECT STATEMENT 1 TABLE ACCESS 2 INDEX OPTIONS OBJECT_NAME -------------------- ------------------. BY INDEX ROWID TESTE.TAB_LOC UNIQUE SCAN TESTE.TAB_LOC_PK
Range Scan: usado para obter um determinado intervalo de dados. Retorna 0 ou mais rowids.
OPERATION ------------------------0 SELECT STATEMENT 1 TABLE ACCESS 2 INDEX OPTIONS OBJECT_NAME -------------------- -------------------. BY INDEX ROWID TESTE.TAB_LOC RANGE SCAN TESTE.TAB_LOC_DATA
Full Scan: usado quando a query usa pelo menos uma coluna do ndice. Tambm usado quando a consulta no possui predicado e se deseja evitar a operao de sort.
Fast Full Scan: um Full Table Scan alternativo usado quando o ndice possui todas colunas necessrias para a query. Para ler todos dados do ndice, mais rpido que o Index Scan por possibilitar o Multiblock I/O e a paralelizao. Obs: no pode ser usado para evitar a operao de sort (os dados no so retornados de forma ordenada).
OPERATION OPTIONS ------------------------- -------------------0 SELECT STATEMENT 1 INDEX FAST FULL SCAN OBJECT_NAME ------------------. TESTE.TAB_LOC_DATA
Index Join: um hash join com alguns ndices da tabela. Juntos obtm todas colunas referenciadas na query.
OPERATION ------------------------0 SELECT STATEMENT 1 VIEW 2 HASH JOIN 3 INDEX 4 INDEX OPTIONS OBJECT_NAME ----------------- ----------------------. TESTE.index$_join$_001 . FAST FULL SCAN TESTE.TAB_LOC_DATA FAST FULL SCAN TESTE.TAB_LOC_PK
Bitmap: utiliza um bitmap como chave para cada valor distinto da coluna e uma funo de mapeamento que converte cada bit para um rowid. Se a coluna indexada tiver baixa cardinalidade, so rpidos e ocupam pouco espao. Obs: uma coluna considerada de baixa cardinalidade se o nmero de valores distintos for menor ou igual a 1% do total de registros.
OPERATION ------------------------0 SELECT STATEMENT 1 TABLE ACCESS 2 BITMAP CONVERSION 3 BITMAP INDEX OPTIONS OBJECT_NAME -------------------- -------------------. BY INDEX ROWID TESTE.VENDAS TO ROWIDS . SINGLE VALUE TESTE.VENDAS_TIPO_BM
2. Tipos de Join
O join uma operao que permite combinar o resultado de duas ou mais tabelas baseando se nos valores das colunas em comum. O Oracle utiliza os seguintes algoritmos
select * from tab_loc l, tab_loc_peq p where l.codigo = p.codigo; OPERATION ------------------------0 SELECT STATEMENT 1 NESTED LOOPS 2 TABLE ACCESS 3 TABLE ACCESS 4 INDEX OPTIONS OBJECT_NAME -------------------- -----------------. . FULL TESTE.TAB_LOC_PEQ BY INDEX ROWID TESTE.TAB_LOC UNIQUE SCAN TESTE.TAB_LOC_PK
2.2 Sort-Merge
Os registros de cada tabela so ordenados pelas colunas do join condition feito um merge das duas ordenaes e os registros que satisfizerem o join condition so 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 no precisou realizar o sort porque o range scan j retornou os dados ordenados.
select /*+ use_hash(l) */ * from tab_loc l, tab_loc_peq p where l.codigo = p.codigo; OPERATION ------------------------0 SELECT STATEMENT 1 HASH JOIN 2 TABLE ACCESS 3 TABLE ACCESS OPTIONS OBJECT_NAME -------------------- -------------------. . FULL TESTE.TAB_LOC_PEQ FULL TESTE.TAB_LOC
bitmap das colunas FKs da tabela fato para obter o result set (conjunto exato dos registros necessrios para avaliar a consulta). Em seguida os registros da tabela fato so obtidos. 2. O join entre a tabela fato e as dimenses realizado. Geralmente o hash join o mais eficiente. Exemplo:
W H s = r ot
3. Hints
Hint um comentrio padronizado que se inclui no meio do comando para modificar o plano de execuo. Geralmente ele utilizado nos casos em que o Oracle no consegue definir uma boa estratgia. Sintaxe: select /*+ Hint... */ colunas ... from tabelas ... Abaixo segue a listagem dos hints para consultas:
Hash_Aj transforma o NOT IN subquery em hash anti-join Merge_Sj - transforma o EXISTS em sort-merge semi-join mantendo a semntica. O default do EXISTS usar o algoritmo nested loops. Obs: nos casos em que a tabela que est sendo verificada (tabela dentro do EXISTS) no possuir ndice nas colunas do join, haver um ganho de performance se o sort-merge semijoin for usado. Hash_Sj transforma o EXISTS em hash semi-join mantendo a semntica. O default do EXISTS usar o algoritmo nested loops. Obs: nos casos em que a tabela que est sendo verificada (tabela dentro do EXISTS) no possuir ndice nas colunas do join, haver um ganho de performance se o hash semi-join for usado. Push_Join_Pred(v) fora a view usar o join predicate da query principal
3.3 Acesso
Full(tab) fora o full table scan para tabela tab Cache(tab) fora 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 parmetro CACHE_SIZE_THRESHOLD.
Nocache(tab) fora que os blocos retornados da consulta no sejam colocados na cache, mesmo que a tabela tenha o parmetro cache habilitado. Rowid(tab) fora o acesso a tabela tab pelo rowid Index(tab index) fora 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 invs do full table scan Index_Combine(tab i1.. i5) realiza a combinao booleana de ndices bitmap com melhor custo. Index_join(tab i1.. i5) induz a utilizao index join And_Equal(tab i1.. i5) realiza o merge de 2 a 5 ndices com apenas 1 coluna. Use_Concat transforma a combinao de ORs/IN na clusula WHERE em uma query composta com operador de conjunto UNION ALL. No_Expand no permite a concatenao 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 mtodo sort-merge. Use_Hash(tab) induz o Oracle a realizar o join da tabela tab com o mtodo 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 transformao s realizada se for benfico. Ordered induz o Oracle a executar o join na ordem em que as tabelas se encontram na clusula FROM (da esquerda para direita e de cima para baixo).
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 paralelizao do acesso a tabela tab Noparallel_Index(tab) evita o parallel index scan
3.7 Variados
Rewrite(v1[,v2]) permite que uma query compatvel com a consulta de uma materialized view (v1,v2,...) seja reescrita de forma que aproveite os dados pr processados da materialized view. Obs: verso posterior a 8.1 Norewrite no 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 -----------------------CODIGO DESCRICAO DATA VALOR Null? -------NOT NULL NOT NULL NOT NULL NOT NULL Type -------------VARCHAR2(10) VARCHAR2(50) DATE NUMBER
tab_loc_peq: tabela local pequena ndices : tab_loc_peq_pk (codigo) registros: 50 SQL> desc tab_loc_peq Name -----------------------CODIGO DESCRICAO DATA VALOR Null? -------NOT NULL NOT NULL NOT NULL NOT NULL Type -------------VARCHAR2(10) VARCHAR2(50) DATE NUMBER
tab_loc_gra: tabela local grande ndices : tab_loc_gra_pk (codigo) registros: 3.070.307 SQL> desc tab_loc_peq Name -----------------------CODIGO DESCRICAO DATA VALOR Null? -------NOT NULL NOT NULL NOT NULL NOT NULL Type -------------NUMBER(10) VARCHAR2(50) DATE NUMBER
tab_rem@link_bci: tabela remota ndices : tab_rem_pk (codigo) registros: 500.000 SQL> desc tab_rem@link_bci Name Null? ------------------------ -------CODIGO NOT NULL DESCRICAO NOT NULL DATA NOT NULL VALOR NOT NULL Type -----------VARCHAR2(10) VARCHAR2(50) DATE NUMBER
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 -----------------------------0 SELECT STATEMENT 1 SORT 2 INDEX OPTIONS OBJECT_NAME -------------------- -----------------. AGGREGATE . 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
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 -----------------------------0 SELECT STATEMENT 1 HASH JOIN 2 TABLE ACCESS 3 INDEX 4 TABLE ACCESS OPTIONS OBJECT_NAME -------------------- ---------------------. . BY INDEX ROWID TESTE.TAB_LOC_GRA RANGE SCAN TESTE.TAB_LOC_GRA_DATA 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
Incluso da converso explcita de tipo select count(*) from tab_loc_gra g, tab_loc l where l.codigo = and g.data Resultado Tempo: 0,4s Obs: Apenas incluindo a converso de tipo, o tempo foi reduzido pela metade. Note que o plano de execuo no foi alterado.
VARCHAR2 */
to_char(g.codigo,'fm99999999')
/*
ambos
= to_date('10/10/2003','dd/mm/yyyy');
OPERATION -----------------------------0 SELECT STATEMENT 1 SORT 2 HASH JOIN 3 TABLE ACCESS 4 INDEX 5 INDEX
OPTIONS OBJECT_NAME -------------------- ----------------------. AGGREGATE . . BY INDEX ROWID TESTE.TAB_LOC_GRA RANGE SCAN TESTE.TAB_LOC_GRA_DATA 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
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 ---------------------------0 SELECT STATEMENT 1 SORT 2 NESTED LOOPS 3 TABLE ACCESS 4 INDEX 5 INDEX OPTIONS OBJECT_NAME -------------------- -------------------. AGGREGATE . . BY INDEX ROWID TESTE.TAB_LOC_GRA RANGE SCAN TESTE.TAB_LOC_GRA_DATA 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
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
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;
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) Desative o timed_statistics
alter system set timed_statistics=false;
5) Localize o trace gerado (sempre no servidor) o Os traces sero gerados no diretrio definido para o parmetro USER_DUMP_DEST. Para identific-lo execute:
select value from v$parameter where name = 'user_dump_dest';
O nome do comando:
arquivo
pode
ser
obtido
com
sguinte
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>;
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