Professional Documents
Culture Documents
Posted by ricardo@nervinformatica.com.br
http://nervinformatica.com.br/blog/index.php/2014/05/28/sql-tuning-quando-ocorre-um-full-table-scan/
Os fatores que influenciam o CBO na decisão sobre utilizar um índice, ou executar um Full Table
Scan são três:
Ou seja, não é apenas o percentual dos dados retornados pela consulta em relação ao total da
tabela.
Vamos comprovar, criando duas tabelas idênticas em estrutura, e que possuem os mesmos dados,
mas distribuídos de forma diferente.
Estas duas tabelas terão um índice do mesmo tipo e na mesma coluna, e as estatísticas serão
coletadas da mesma forma para ambas.
C:UsersRicardo>sqlplus SCOTT/TIGER
Tabela criada.
índice criado.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT', 'T1', METHOD_OPT=>'FOR ALL COLUMNS SIZE
1', CASCADE=>TRUE);
SQL> CREATE TABLE T2 AS SELECT MOD(ROWNUM,100) ID, RPAD(ROWNUM,100) NAME FROM DBA_SOURCE
WHERE ROWNUM <= 10000;
Tabela criada.
Índice criado.
SQL>
Vejam que as tabela possuem a mesma quantidade de linhas, e também a mesma quantidade de
linhas com o valor 1 na coluna ID, assim como a quantidade de linhas com o valor menor que 5. Na
verdade, as tabelas são idênticas em todas as linhas.
COUNT(*)
----------
10000
COUNT(*)
----------
10000
COUNT(*)
----------
100
COUNT(*)
----------
100
COUNT(*)
----------
500
COUNT(*)
----------
500
COUNT(*)
----------
1000
COUNT(*)
----------
1000
SQL>
Vamos então ver alguns planos de execução. Primeiramente, vamos ver o método de acesso que o
CBO escolhe para uma seletividade de 1% de cada tabela.
Plano de Execução
----------------------------------------------------------
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
---------------------------------------------------
2 - access("ID"=1)
Estatísticas
----------------------------------------------------------
1 recursive calls
0 db block gets
19 consistent gets
0 physical reads
0 redo size
0 sorts (memory)
0 sorts (disk)
Plano de Execução
----------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
---------------------------------------------------
1 - filter("ID"=1)
Estatísticas
----------------------------------------------------------
1 recursive calls
0 db block gets
0 physical reads
0 redo size
0 sorts (memory)
0 sorts (disk)
SQL>
Epa, como os métodos de acesso são diferentes para dados iguais? E como o índice não é utilizado
para a tabela T2, se estou solicitando apenas 1% da tabela?
Vamos repetir o teste com 5% das linhas das tabelas.
Plano de Execução
----------------------------------------------------------
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
| 1 | INLIST ITERATOR | | | | | |
----------------------------------------------------------------------------------------
---------------------------------------------------
Estatísticas
----------------------------------------------------------
0 recursive calls
0 db block gets
88 consistent gets
0 physical reads
0 redo size
0 sorts (memory)
0 sorts (disk)
Plano de Execução
----------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
---------------------------------------------------
Estatísticas
----------------------------------------------------------
0 recursive calls
0 db block gets
0 physical reads
0 redo size
0 sorts (memory)
0 sorts (disk)
SQL>
Plano de Execução
----------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
---------------------------------------------------
Estatísticas
----------------------------------------------------------
0 recursive calls
0 db block gets
0 physical reads
0 redo size
0 sorts (memory)
0 sorts (disk)
Plano de Execução
----------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
---------------------------------------------------
Estatísticas
----------------------------------------------------------
1 recursive calls
0 db block gets
215 consistent gets
0 physical reads
0 redo size
0 sorts (memory)
0 sorts (disk)
SQL>
Agora chegamos a um ponto onde os métodos de acesso são iguais para as duas tabelas, e isto
aconteceu para a T1 até antes do lendário limite de 10% de seletividade para uso de índice.
20 1 152
20 1 10000
SQL>
Por causa da forma da alimentação dos dados na tabela (TRUNC((ROWNUM-1)/100) na T1, versus
MOD(ROWNUM,100) na T2), as linhas com o mesmo valor (por exemplo, 1) na coluna ID ficaram
todas juntas na tabela T1, no nível de bloco, enquanto na tabela T2 uma linha com o valor 1 na
coluna ID ficou longe (em outro bloco) da próxima linha com o valor 1. Ou seja, na T2 os dados
estão espalhados, enquanto o índice é ordenado. Logo, chega um momento em que o CBO vê que é
mais custoso percorrer entrada a entrada do índice, para buscar blocos não contíguos na tabela.
Índice alterado.
Índice alterado.
20 1 152
20 1 10000
SQL>
Absolutamente nada. Isto acontece porque o Clustering Factor se refere a ordenação de dados na
tabela, e esta não foi alterada.
Tabela criada.
Índice criado.
20 1 152
SQL>
Veja que isto não necessariamente tornaria o SQL mais rápido, apenas faria com que o plano de
execução utilizasse outro método de acesso. E se a tabela tivesse mais índices, em outras colunas,
você provavelmente estaria aumentando o Clustering Factor de outro índice.
Em resumo: para SQL Tuning, o DBA deve não só conhecer os dados, mas como eles são
armazenados, e de que forma são selecionados.