Escolar Documentos
Profissional Documentos
Cultura Documentos
Fatos
Questes Preliminares
Otimizao por Custo e Regra
Gerando Estatsticas
Package DBMS_STATS
Gerando Estatsticas com OEM
Hints
Senso Comum em SQL
Driving Table
Uso Eficiente de Clusulas Where No Indexadas
Usando ROWID
Reduzindo o Nmero de Acessos ao Banco
Usando DECODE
Cuidados na Clusula WHERE
Dicas
Casos Especiais
1. Fatos
Alguns fatos sobre melhoria de performance em consultas:
Melhoras no tempo de resposta so possveis atravs da tentativa e erro;
fundamental estudar e conhecer o projeto do seu banco de dados;
Durante o tunning possvel degradar a performance, ao invs de melhor-la;
importante isolar o problema, identificando as consultas SQL.
2. Questes Preliminares
Algumas questes surgem:
Quando algo realmente demorado?
A consulta est sendo executada em volumes reais de produo?
Est sendo realmente usado o plano de acesso gerado pelo otimizador?
Existem eventos ou mudanas no banco de dados que podem afetar a performance?
Custo:
Seu comportamento orientado pelas informaes estatsticas disponveis sobre os
objetos envolvidos, bem como o dicionrio de dados. O otimizador define o plano de
acesso, que pode ser modificado manualmente com o uso do hints.
4. Gerando Estatsticas
Conhecido como CBO (Cost Based Optimizer), o otimizador o responsvel pela gerao
dos planos de acesso para a execuo das consultas.
Ele depende de estatsticas precisas sobre os objetos existentes no banco. Ele precisa
conhecer detalhadamente os objetos existentes no banco de dados, para gerar planos de
acesso eficientes.
Para isto ele estabelece um ranque baseado no critrio de menor custo, determinado pelo
consumo de I/O, memria e CPU.
Estatsticas podem ser geradas atravs da package DBMS_STATS.
5. Package DBMS_STATS
A package DBMS_STATS possui diversas procedures para realizar a coleta de estatstica
em diferentes nveis. As opes so as seguintes:
GATHER_DATABASE_STATISTICS
Gera estatstica para todos os objetos do banco.
GATHER_SCHEMA_STATISTICS
Gera estatstica para um schema.
GATHER_TABLE_STATISTICS
Gera estatstica para uma tabela e seus ndices.
GATHER_INDEX_STATISTICS
Gera estatstica para um ndice.
Tabela
SQL> EXECUTE DBMS_STATS.GATHER_TABLE_STATS ('admin','cliente');
PL/SQL procedure successfully completed.
SQL>
Banco de dados
SQL> EXECUTE dbms_stats.gather_database_stats (> ESTIMATE_PERCENT => NULL, > METHOD_OPT => 'AUTO', > GRANULARITY => 'ALL', > CASCADE => 'TRUE',> OPTIONS => 'GATHER AUTO');
PL/SQL procedure successfully completed.
SQL>
7. Hints
possvel realizar tunning de uma consulta manualmente, atravs do uso de hints. Com ele
possvel sobrepor as decises do otimizador, definindo como deve ser a estratgia de
execuo da consulta.
Colocando os hints (dicas) de otimizao como comentrios em um comando SQL, ele
forado a seguir o plano que voc definiu, ao invs de utilizar o que foi definido pelo
otimizador.
Seu uso:
SELECT /*+ texto do hint */ .....
UPDATE /*+ texto do hint */ ....
DELETE /*+ texto do hint */ .....
Ex.:
7. Hints (continuao)
Por que hints podem ser ignorados?
1) Escrita errada
2) Hint inapropriado
SELECT /*+ index(dept dpt_pk) */
FROM emp
WHERE emp_no = 12345
3) Conflito
SELECT /*+ index(emp dpt_idx) */
FROM emp
WHERE emp_no = 12345
tabela errada
7. Hints (continuao)
Hints mais utilizados:
INDEX
Usado para forar a utilizao de um ou mais ndices no plano de acesso gerado pelo
otimizador.
Sintaxe:
select /*+ INDEX (table index1, index2) */ column1,
Exemplo:
select /*+ INDEX (emp deptno_idx) */ empno, ename, deptno
from emp
where deptno = 1;
select /*+ INDEX (emp deptno_idx, empno_idx) */ empno, ename, deptno
from emp
where deptno = 1
and empno = 7750;
7. Hints (continuao)
ORDERED
Determina a ordem de acesso que deve ser observada para acesso as tabelas
especificadas na clusula FROM.
Sintaxe:
select /*+ ORDERED */ column1,
Exemplo:
select /*+ ORDERED */ emp.empno, ename, dept.deptno, itemno
from emp, dept, orders
where emp.deptno = dept.deptno
and emp.empno = orders.empno
and dept.deptno = 1
and emp.empno = 7747
and orders.ordno = 45;
7. Hints (continuao)
FIRST_ROWS
O otimizador ir escolher o plano de acesso que retore mais rapidamente a quantidade de
linhas especificadas.
A consulta no pode ser do tipo INSERT, UPDATE ou DELETE. Seu uso tambm
ignorado quando se usa GROUP BY, DISTINCT, INTERSECT, MINUS e UNION.
Sintaxe:
select /*+ FIRST_ROWS(n) */ column1,
Exemplo:
select /*+ FIRST_ROWS */ empno, ename, deptno
from emp
where deptno = 1;
select /*+ FIRST_ROWS(10) */ empno, ename, deptno
from emp
where deptno = 1;
7. Hints (continuao)
FULL
Faz com que o otimizador execute um full table scan na tabela especificada.
Sintaxe:
select /*+ FULL(table) */ column1,
Exemplo:
select /*+ FULL(emp) */ empno, ename, deptno
from emp
where deptno = 1;
7. Hints (continuao)
NO_INDEX
Impede que o otimizador utilize um determinado ndice.
Sintaxe:
select /*+ NO_INDEX (table index1, index2) */ column1,
Exemplo:
select /*+ NO_INDEX (emp deptno_idx) */ ename, deptno
from emp
where deptno = 1;
7. Hints (continuao)
USE_NL
USE_NL (use nested loops) a forma mais rpida de retornar uma linha, levando em
considerao o tempo de resposta. Ele pega a linha de uma tabela (que atende a condio
requerida) e junta (join) com o resultado de uma segunda tabela.
Sintaxe:
select /*+ USE_NL (table1, table2,) */ column1,
Exemplo:
select /*+ ORDERED USE_NL(dept) */ empno, ename, dept.deptno
from emp, dept
where emp.deptno = dept.deptno
and dept.deptno = 1
and emp.empno = 7747;
7. Hints (continuao)
USE_HASH
a forma mais rpida de fazer join entre muitas linhas de mltiplas tabelas, se houver
memria suficiente para suportar a operao. Parecido com o USE_NL, com a excesso de
colocar toda a segunda tabela na memria.
Os parmetros de inicializao HASH_AREA_SIZE e PGA_AGGREGATE_TARGET
precisam ser dimensionados apropriadamente para suportar estas operaes, seno ela
ocorrer em disco.
Sintaxe:
select /*+ USE_HASH (table1, table2,...) */ column1,
Exemplo:
select /*+ USE_HASH (dept) */ empno, ename, dept.deptno
from emp, dept
where emp.deptno = dept.deptno
and emp.empno = 7747;
7. Hints (continuao)
PARALLEL
Faz o otimizador quebrar a consulta em pequenos pedaos (degree) e processar cada uma
com um diferente server process. Uma consulta que realize operaes de sort ir utilizar o
dobro de server process especificados.
Sintaxe:
/*+ PARALLEL (table, DEGREE) */
degree o nmero de pedaos em que a consulta ser quebrada.
Se no for especificado, ser utilizado o valor default definido na criao da tabela.
Exemplo:
select /*+ PARALLEL (order_line_items) */ invoice_number, invoice_date
from order_line_items
order by invoice_date;
select /*+ PARALLEL (order_line_items, 4) */ invoice_number, invoice_date
from order_line_items
order by invoice_date;
7. Hints (continuao)
APPEND
Aumenta a performance de comandos de INSERT, mas com o potencial custo em termos de
espao.
Ele no verifica se h espao livre nos blocos j utilizados pela tabela, inserindo dados
somente em blocos novos. Espao acaba sendo desperdiado, mas a execuo do
comando se torna mais rpida.
Se uma tabela nunca sofre excluso de linhas, este hint deve ser utilizado.
Sintaxe:
insert /*+ APPEND */
Exemplo:
insert /*+ APPEND */
into emp (empno, deptno)
values (7747, 10);
9. Driving Table
O objetivo em qualquer comando SQL minimizar o nmero de leituras a disco que
precisam ser feitas.
Geralmente os comandos SQL possuem mais de uma tabela relacionada na clusula
FROM. Uma delas ser a primeira a ser acessada. A ela chamamos de driving table.
Fazendo a escolha correta, ganhos de performance podem ser alcanados. Para defini-la,
coloque-a como a ltima tabela da clusula FROM.
Ex.: TAB1: 16.384 linhas
TAB2:
1 linha
SELECT COUNT(*) FROM TAB1, TAB2
SELECT COUNT(*) FROM TAB2, TAB1
SELECT .....
10,6 segundos
FROM emp E
WHERE 25 < (SELECT COUNT(*) FROM emp WHERE emp_mgr = E.emp_no)
AND
emp_salary > 50.000
AND
emp_type = MANAGER
Cenrio 1
SELECT COUNT(*), SUM(salary) FROM emp
WHERE dept_no = 20 and emp_name LIKE SMITH%;
SELECT COUNT(*), SUM(salary) FROM emp
WHERE dept_no = 30 and emp_name LIKE SMITH%
Cenrio 2
SELECT COUNT(DECODE(dept_no, 20, X, NULL)) D20_COUNT,
COUNT(DECODE(dept_no, 30, X, NULL)) D30_COUNT,
SUM(DECODE(dept_no, 20, salary, NULL)) D20_SAL,
SUM(DECODE(dept_no, 30, salary, NULL)) D30_SAL
FROM emp WHERE emp_name LIKE SMITH%
Cenrio 1
No use
SELECT account_name, trans_date, amount
FROM transaction
WHERE SUBSTR(account_name,1,7) = CAPITAL;
Use
SELECT account_name, trans_date, amount
FROM transaction
WHERE account_name LIKE CAPITAL%;
Cenrio 2
No use
SELECT account_name, trans_date, amount
FROM transaction
WHERE amount != 0;
Use
SELECT account_name, trans_date, amount
FROM transaction
WHERE amount > 0;
Cenrio 3
No use
SELECT account_name, trans_date, amount
FROM transaction
WHERE trunc(trans_date) = TRUNC(sysdate);
Use
SELECT account_name, trans_date, amount
FROM transaction
WHERE trans_date between TRUNC(sysdate) and TRUNC(sysdate) + .99999;
Cuidado
SELECT TO_DATE(01/01/2010) + .99999 01/01/2010 23:59:59
SELECT TO_DATE(01/01/2010) + .999999 02/01/2010 00:00:00
Cenrio 4
No use
SELECT account_name, trans_date, amount
FROM transaction
WHERE account_name || account_type = AMEXA;
Use
SELECT account_name, trans_date, amount
FROM transaction
WHERE account_name = AMEX
AND
account_type = A;
Cenrio 5
No use
SELECT account_name, trans_date, amount
FROM transaction
WHERE amount + 3000 < 5000;
Use
SELECT account_name, trans_date, amount
FROM transaction
WHERE amount < 2000;
Cenrio 6
No use
SELECT account_name, trans_date, amount
FROM transaction
WHERE account_name = NVL(:acc_name, account_name);
Use
SELECT account_name, trans_date, amount
FROM transaction
WHERE account_name = NVL(:acc_name, %);
15. Dicas
Realizar tunning de um comando ou grupo de comandos SQL mais uma batalha do que
propriamente arte. Somente poucas pessoas conseguem fazer isto simplesmente por
instinto.
Somente a experincia e observao faro com que bons resultados sejam alcanados,
consolidando o conhecimento acerca deste assunto. necessrio ser persistente.
Sero vistas agoras algumas dicas para situaes que podem ocorrer no dia-a-dia do DBA.
mais rpida
5% mais lento
Evite
SELECT emp_name
FROM emp
WHERE emp_cat = (SELECT MAX(category) FROM emp_categories)
AND sal_range = (SELECT MAX(sal_range) FROM emp_categories)
AND emp_dept = 0020;
Use
SELECT emp_name
FROM emp
WHERE (emp_cat, sal_range) = (SELECT MAX(category), MAX(sal_range)
FROM emp_categories)
AND emp_dept = 0020;
SELECT X
FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = A);
Use
SELECT emp_name
FROM emp E, dept D
WHERE E.dept_no = D.dept_no
AND
D.dept_cat = A
Use
SELECT
FROM emp
WHERE NOT EXISTS
SELECT X
FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = A);
Nestas situaes um full table scan pode ocorrer. O problema pode ser pior se
considerarmos joins entre tabelas cujos campos possuem datatypes diferentes.
SELECT .....
FROM emp, sales
WHERE emp.emp_no = sales.emp_no